├── .gitignore ├── LICENSE ├── README.md ├── bower.json ├── interviews ├── refactor.cp.js └── refactor.js ├── package.json ├── schemas ├── aliasRedirects.sql ├── anchors.sql ├── answers.sql ├── changeLogs.sql ├── contentRequests.sql ├── discussionSubscriptions.sql ├── domainFriends.sql ├── domainMembers.sql ├── domains.sql ├── feedPages.sql ├── helpers │ ├── changes.sql │ ├── create_reqs.sql │ └── create_reqs2.sql ├── invites.sql ├── lastViews.sql ├── lastVisits.sql ├── lenses.sql ├── likeableIds.sql ├── likes.sql ├── links.sql ├── maintainerSubscriptions.sql ├── marks.sql ├── pageInfos.sql ├── pagePairs.sql ├── pageSummaries.sql ├── pageToDomainSubmissions.sql ├── pages.sql ├── pathInstances.sql ├── pathPages.sql ├── projects.sql ├── redLinks.sql ├── searchStrings.sql ├── updates.sql ├── userMasteryPairs.sql ├── userPageObjectPairs.sql ├── userRequisitePairSnapshots.sql ├── userSubscriptions.sql ├── users.sql ├── visits.sql └── votes.sql ├── scripts ├── build_gomon.sh ├── check_deps.go ├── configs_identical.sh ├── create_daemon_user.sh ├── create_db.sh ├── create_monitoring_vm.sh ├── create_pages.sh ├── db_shell.sh ├── decrypt_config.sh ├── decrypt_config_remote.sh ├── deploy_ae.sh ├── deploy_queue.sh ├── encrypt_config.sh ├── file_watcher.patch ├── gcloud_bashrc.sh ├── gcloud_bootstrap_init.sh ├── import_keys.sh ├── init.sh ├── local_mysql.sh ├── needs_gofmt.sh ├── patch_appengine.sh ├── pre-commit.sh ├── pre-push.sh ├── run_gomon.sh ├── run_monitoring.sh ├── run_prober.sh ├── run_tests.sh ├── setup_valid_db.sh ├── stage.sh ├── style_js.sh ├── symlink_git_hooks.sh ├── update_db.sh ├── update_vm_manifest.sh └── v2_stage.sh ├── src ├── .vscode │ └── settings.json ├── config │ ├── config.go │ ├── config_test.go │ └── init.go ├── core │ ├── constants.go │ ├── currentUser.go │ ├── databaseUtils.go │ ├── domains.go │ ├── feed.go │ ├── lastViewHelpers.go │ ├── likeables.go │ ├── page.go │ ├── pageLoadOptions.go │ ├── pagePair.go │ ├── pageUtils.go │ ├── permission.go │ ├── update.go │ └── user.go ├── database │ ├── database.go │ ├── dbcore │ │ └── core.go │ └── queryPart.go ├── elastic │ └── elastic.go ├── facebook │ └── facebook.go ├── logger │ └── logging.go ├── mailchimp │ └── mailchimp.go ├── okta │ └── okta.go ├── pages │ └── pages.go ├── queue_daemon │ ├── init.go │ └── module.yaml ├── sessions │ ├── context.go │ ├── creds.go │ ├── error.go │ └── init.go ├── site │ ├── adminTaskHandler.go │ ├── app.yaml │ ├── approveCommentHandler.go │ ├── approvePageEditProposalHandler.go │ ├── approvePageToDomainHandler.go │ ├── bellUpdatesHandler.go │ ├── changeSpeedHandler.go │ ├── childrenJsonHandler.go │ ├── commentThreadHandler.go │ ├── continueWritingModeHandler.go │ ├── dashboardPageJsonHandler.go │ ├── defaultJsonHandler.go │ ├── deleteAnswerHandler.go │ ├── deleteLensHandler.go │ ├── deletePageHandler.go │ ├── deletePagePairHandler.go │ ├── deletePathPageHandler.go │ ├── deleteSearchStringHandler.go │ ├── discardPageHandler.go │ ├── discussionModeHandler.go │ ├── dismissUpdateHandler.go │ ├── domainPageJsonHandler.go │ ├── domainsHandler.go │ ├── dynamicPage.go │ ├── editJsonHandler.go │ ├── editPageHandler.go │ ├── editPageInfoHandler.go │ ├── exploreHandler.go │ ├── externalUrlHandler.go │ ├── feedPageHandler.go │ ├── feedbackHandler.go │ ├── forgotPasswordHandler.go │ ├── handler.go │ ├── hedonsModeHandler.go │ ├── indexJsonHandler.go │ ├── init.go │ ├── intrasitePopoverJsonHandler.go │ ├── learnJsonHandler.go │ ├── learnJsonHandler_test.go │ ├── lensJsonHandler.go │ ├── loginHandler.go │ ├── mailchimpSignupHandler.go │ ├── maintenanceModeHandler.go │ ├── marksJsonHandler.go │ ├── mergeQuestionsHandler.go │ ├── modeHelpers.go │ ├── monitor.go │ ├── moreRelationshipsJsonHandler.go │ ├── mostTodosJsonHandler.go │ ├── newAnswerHandler.go │ ├── newContentRequestHandler.go │ ├── newFeedPage.go │ ├── newInviteHandler.go │ ├── newLensHandler.go │ ├── newLikeHandler.go │ ├── newMarkHandler.go │ ├── newMemberHandler.go │ ├── newPageHandler.go │ ├── newPagePairHandler.go │ ├── newPageToDomainSubmissionHandler.go │ ├── newPathPageHandler.go │ ├── newSearchStringHandler.go │ ├── newVoteHandler.go │ ├── newsletterJsonHandler.go │ ├── pageHandler.go │ ├── pagePage.go │ ├── pagesWithDraftJsonHandler.go │ ├── parentsJsonHandler.go │ ├── parentsSearchJsonHandler.go │ ├── pendingModeHandler.go │ ├── primaryPageJsonHandler.go │ ├── projectHandler.go │ ├── projectsHandler.go │ ├── queue.yaml │ ├── readModeHandler.go │ ├── recentChangesHandler.go │ ├── recentRelationshipChanges.go │ ├── recentlyCreatedCommentJsonHandler.go │ ├── recentlyEditedJsonHandler.go │ ├── redLinkPopoverHandler.go │ ├── requisitesJsonHandler.go │ ├── resolveMarkHandler.go │ ├── resolveThreadHandler.go │ ├── revertPageHandler.go │ ├── searchJsonHandler.go │ ├── sendSlackInvite.go │ ├── sendTestEmailHandler.go │ ├── settingsPageJsonHandler.go │ ├── signupHandler.go │ ├── similarPageSearchJsonHanlder.go │ ├── startPathHandler.go │ ├── static │ │ ├── html │ │ │ ├── adminDashboardPage.html │ │ │ ├── answers.html │ │ │ ├── autocomplete.html │ │ │ ├── bellUpdatesPage.html │ │ │ ├── changeLogEntry.html │ │ │ ├── changeSpeedButton.html │ │ │ ├── checkbox.html │ │ │ ├── childRelationships.html │ │ │ ├── commentCount.html │ │ │ ├── composeFab.html │ │ │ ├── confirmButton.html │ │ │ ├── dashboardPage.html │ │ │ ├── debatePage.html │ │ │ ├── discussionModePage.html │ │ │ ├── domainCheckup.html │ │ │ ├── domainIndexPage.html │ │ │ ├── domainRoleInput.html │ │ │ ├── domainsPage.html │ │ │ ├── editButton.html │ │ │ ├── editClaimDialog.html │ │ │ ├── editDiff.html │ │ │ ├── editPage.html │ │ │ ├── editPageDialog.html │ │ │ ├── expandIcon.html │ │ │ ├── explorePage.html │ │ │ ├── exploreTreeNode.html │ │ │ ├── feedPage.html │ │ │ ├── feedbackDialog.html │ │ │ ├── footer.html │ │ │ ├── hedonsModePage.html │ │ │ ├── hubPageFooter.html │ │ │ ├── hubPageGui.html │ │ │ ├── indexPage.html │ │ │ ├── inlineComment.html │ │ │ ├── intrasitePopover.html │ │ │ ├── learnMore.html │ │ │ ├── learnPage.html │ │ │ ├── learnPart.html │ │ │ ├── lens.html │ │ │ ├── lensToolbar.html │ │ │ ├── lensToolbarWrapper.html │ │ │ ├── likes.html │ │ │ ├── listPanel.html │ │ │ ├── listSubHeader.html │ │ │ ├── loginPage.html │ │ │ ├── maintenanceModePage.html │ │ │ ├── markInfo.html │ │ │ ├── marks.html │ │ │ ├── masteryList.html │ │ │ ├── multipleChoice.html │ │ │ ├── newsletterPage.html │ │ │ ├── nextPrev.html │ │ │ ├── page.html │ │ │ ├── pageDiscussion.html │ │ │ ├── pageImprovement.html │ │ │ ├── pageList.html │ │ │ ├── pageTitle.html │ │ │ ├── paragraphEditDialog.html │ │ │ ├── pathEditor.html │ │ │ ├── pathNav.html │ │ │ ├── pendingPanel.html │ │ │ ├── primaryPage.html │ │ │ ├── projectPage.html │ │ │ ├── queryInfo.html │ │ │ ├── quickRequisiteDialog.html │ │ │ ├── readModePage.html │ │ │ ├── recentChangesPage.html │ │ │ ├── redLinkPopover.html │ │ │ ├── relationships.html │ │ │ ├── reqRelationships.html │ │ │ ├── requisiteButton.html │ │ │ ├── requisitesPage.html │ │ │ ├── rhsButtons.html │ │ │ ├── rows │ │ │ │ ├── addedToGroupModeRow.html │ │ │ │ ├── changeLogRow.html │ │ │ │ ├── commentModeRow.html │ │ │ │ ├── commentRowInternal.html │ │ │ │ ├── draftRow.html │ │ │ │ ├── editProposalRow.html │ │ │ │ ├── explanationRequestRow.html │ │ │ │ ├── inviteReceivedModeRow.html │ │ │ │ ├── likesModeRow.html │ │ │ │ ├── pageRow.html │ │ │ │ ├── pageToDomainSubmissionRow.html │ │ │ │ ├── removedFromGroupModeRow.html │ │ │ │ ├── reqsTaughtModeRow.html │ │ │ │ ├── taggedForEditRow.html │ │ │ │ ├── updates │ │ │ │ │ ├── atMentionUpdateRow.html │ │ │ │ │ ├── changeLogRowLikeButton.html │ │ │ │ │ ├── commentUpdateRow.html │ │ │ │ │ ├── deletedPageUpdateRow.html │ │ │ │ │ ├── editProposalAcceptedUpdateRow.html │ │ │ │ │ ├── markUpdateRow.html │ │ │ │ │ ├── pageEditUpdateRow.html │ │ │ │ │ ├── pageToDomainAcceptedUpdateRow.html │ │ │ │ │ ├── pageToDomainSubmissionUpdateRow.html │ │ │ │ │ ├── questionMergedUpdateRow.html │ │ │ │ │ ├── relationshipUpdateRow.html │ │ │ │ │ ├── resolvedThreadUpdateRow.html │ │ │ │ │ ├── settingsUpdateRow.html │ │ │ │ │ ├── updateRowDismissButton.html │ │ │ │ │ └── updateRowExpandButton.html │ │ │ │ └── userTrustModeRow.html │ │ │ ├── settingsPage.html │ │ │ ├── signupPage.html │ │ │ ├── slackButton.html │ │ │ ├── subpage.html │ │ │ ├── subscribeToDiscussion.html │ │ │ ├── subscribeToMaintain.html │ │ │ ├── subscribeToUser.html │ │ │ ├── summaryEditDialog.html │ │ │ ├── tableOfContents.html │ │ │ ├── textPopover.html │ │ │ ├── toolbar.html │ │ │ ├── userName.html │ │ │ ├── userPage.html │ │ │ ├── userPopover.html │ │ │ ├── voteBar.html │ │ │ ├── voteSummary.html │ │ │ └── writeNewPanel.html │ │ ├── icons │ │ │ ├── arbital-logo.svg │ │ │ ├── comment-plus-outline.svg │ │ │ ├── comment-question-outline.svg │ │ │ ├── cursor-pointer.svg │ │ │ ├── facebook-box.svg │ │ │ ├── favicon.ico │ │ │ ├── file-outline.svg │ │ │ ├── format-header-pound.svg │ │ │ ├── hand-pointing-right.svg │ │ │ ├── link-variant.svg │ │ │ ├── slack.svg │ │ │ ├── thumb-down-outline.svg │ │ │ ├── thumb-up-outline.svg │ │ │ └── visibility-outline.svg │ │ ├── images │ │ │ ├── arbital-icon-120.png │ │ │ ├── default-image-link.png │ │ │ ├── ic_border_color_black_24dp_1x.png │ │ │ └── math.png │ │ ├── js │ │ │ ├── .jscsrc │ │ │ ├── Markdown.Converter.ts │ │ │ ├── Markdown.Editor.ts │ │ │ ├── Markdown.Sanitizer.ts │ │ │ ├── adminDashboardPage.ts │ │ │ ├── analyticsService.ts │ │ │ ├── angular.ts │ │ │ ├── answers.ts │ │ │ ├── arbDirectives.ts │ │ │ ├── arbService.ts │ │ │ ├── arbital.d.ts │ │ │ ├── arbitalController.ts │ │ │ ├── autocompleteService.ts │ │ │ ├── changeElementType.ts │ │ │ ├── changeSpeedButton.ts │ │ │ ├── checkbox.ts │ │ │ ├── childRelationships.ts │ │ │ ├── dashboardPage.ts │ │ │ ├── debatePage.ts │ │ │ ├── diffService.ts │ │ │ ├── discussionMode.ts │ │ │ ├── domainCheckupPage.ts │ │ │ ├── domainIndexPage.ts │ │ │ ├── domainsPage.ts │ │ │ ├── editClaimDialog.ts │ │ │ ├── editDiff.ts │ │ │ ├── editPage.ts │ │ │ ├── editPageDialog.ts │ │ │ ├── editService.ts │ │ │ ├── explorePage.ts │ │ │ ├── exploreTreeNode.ts │ │ │ ├── feedPage.ts │ │ │ ├── feedbackDialog.ts │ │ │ ├── hedonsMode.ts │ │ │ ├── hiddenText.ts │ │ │ ├── hubPageFooter.ts │ │ │ ├── hubPageGui.ts │ │ │ ├── indexPage.ts │ │ │ ├── inlineCommentUtil.ts │ │ │ ├── learnMore.ts │ │ │ ├── learnPage.ts │ │ │ ├── lens.ts │ │ │ ├── lib │ │ │ │ ├── angular-recursion.min.js │ │ │ │ ├── angular-swipe.js │ │ │ │ ├── demo-bundle.js │ │ │ │ ├── js.cookie.js │ │ │ │ ├── moment.min.js │ │ │ │ └── ng-sortable.min.js │ │ │ ├── loginPage.ts │ │ │ ├── markInfo.ts │ │ │ ├── markService.ts │ │ │ ├── markdown.ts │ │ │ ├── markdownService.ts │ │ │ ├── marks.ts │ │ │ ├── masteryList.ts │ │ │ ├── masteryService.ts │ │ │ ├── mathjax.ts │ │ │ ├── multipleChoice.ts │ │ │ ├── newsletterPage.ts │ │ │ ├── page.ts │ │ │ ├── pageDiscussion.ts │ │ │ ├── pageImprovement.ts │ │ │ ├── pageService.ts │ │ │ ├── paragraphEditDialog.ts │ │ │ ├── pathEditor.ts │ │ │ ├── pathNav.ts │ │ │ ├── pathService.ts │ │ │ ├── popoverService.ts │ │ │ ├── popupService.ts │ │ │ ├── primaryPage.ts │ │ │ ├── projectPage.ts │ │ │ ├── queryInfo.ts │ │ │ ├── quickRequisiteDialogController.ts │ │ │ ├── readMode.ts │ │ │ ├── recentChanges.ts │ │ │ ├── relationships.ts │ │ │ ├── reqRelationships.ts │ │ │ ├── requisitesPage.ts │ │ │ ├── rhsButtons.ts │ │ │ ├── settingsPage.ts │ │ │ ├── signupPage.ts │ │ │ ├── signupService.ts │ │ │ ├── stateService.ts │ │ │ ├── subpage.ts │ │ │ ├── summaryEditDialogController.ts │ │ │ ├── tableOfContents.ts │ │ │ ├── toolbar.ts │ │ │ ├── tsconfig.json │ │ │ ├── typings.json │ │ │ ├── untitled │ │ │ ├── updateRows.ts │ │ │ ├── updatesMode.ts │ │ │ ├── urlService.ts │ │ │ ├── userPage.ts │ │ │ ├── userService.ts │ │ │ ├── util.ts │ │ │ ├── voteBar.ts │ │ │ └── writeMode.ts │ │ ├── scss │ │ │ ├── arbital.scss │ │ │ ├── buttons.scss │ │ │ ├── changeSpeedButton.scss │ │ │ ├── constants.scss │ │ │ ├── ng-material.scss │ │ │ ├── ng-sortable.scss │ │ │ └── util.scss │ │ ├── updatesEmailInlined.html │ │ └── updatesEmailTemplate.html │ ├── titleJsonHandler.go │ ├── tmpl │ │ └── dynamicPage.tmpl │ ├── tsx │ ├── unassessedPagesHandler.go │ ├── updateDomainHandler.go │ ├── updateDomainRoleHandler.go │ ├── updateLensNameHandler.go │ ├── updateLensOrderHandler.go │ ├── updateMarkHandler.go │ ├── updateMasteriesHandler.go │ ├── updateMasteriesOldHandler.go │ ├── updateMemberHandler.go │ ├── updatePageObjectHandler.go │ ├── updatePagePairHandler.go │ ├── updatePathHandler.go │ ├── updatePathOrderHandler.go │ ├── updateSettingsHandler.go │ ├── updateSubscriptionHandler.go │ ├── userPopoverJsonHandler.go │ ├── userSearchJsonHandler.go │ ├── verifyEmailPage.go │ ├── webpack │ │ ├── base.config.js │ │ ├── dev.config.js │ │ ├── entry.js │ │ └── prod.config.js │ └── writeNewModeHandler.go ├── tasks │ ├── atMentionUpdateTask.go │ ├── checkAnsweredMarksTask.go │ ├── copyPagesTask.go │ ├── domainWideNewUpdateTask.go │ ├── emailUpdatesTask.go │ ├── fixTextTask.go │ ├── init.go │ ├── memberUpdateTask.go │ ├── newUpdateTask.go │ ├── populateElasticTask.go │ ├── publishPagePairTask.go │ ├── sendFeedbackEmailTask.go │ ├── sendInviteTask.go │ ├── sendOneEmailTask.go │ ├── task.go │ ├── tickTask.go │ ├── updateElasticPageTask.go │ ├── updateFeaturedPagesTask.go │ ├── updateMetadataTask.go │ └── updatePagePairsTask.go └── v2 │ ├── app.yaml │ ├── dynamicPage.go │ ├── handler.go │ ├── init.go │ ├── pageHandler.go │ ├── static │ └── tsx │ │ └── script.tsx │ ├── tmpl │ └── dynamicPage.tmpl │ └── webpack │ ├── base.config.js │ ├── dev.config.js │ ├── entry.js │ └── prod.config.js ├── test ├── e2e │ ├── README.md │ └── scenarios.js ├── karma.conf.js ├── protractor-conf.js └── unit │ ├── controllersSpec.js │ ├── directivesSpec.js │ ├── filtersSpec.js │ └── servicesSpec.js └── vendor ├── github.com ├── dustin │ └── go-humanize │ │ ├── LICENSE │ │ ├── README.markdown │ │ ├── big.go │ │ ├── bigbytes.go │ │ ├── bytes.go │ │ ├── comma.go │ │ ├── commaf.go │ │ ├── ftoa.go │ │ ├── humanize.go │ │ ├── number.go │ │ ├── ordinals.go │ │ ├── si.go │ │ └── times.go ├── dyatlov │ └── go-opengraph │ │ ├── LICENSE │ │ ├── README.md │ │ ├── examples │ │ ├── advanced.go │ │ └── simple.go │ │ └── opengraph │ │ ├── opengraph.go │ │ └── opengraph_test.go ├── garyburd │ └── go-oauth │ │ └── oauth │ │ └── oauth.go ├── go-sql-driver │ └── mysql │ │ ├── AUTHORS │ │ ├── CHANGELOG.md │ │ ├── CONTRIBUTING.md │ │ ├── ISSUE_TEMPLATE.md │ │ ├── LICENSE │ │ ├── PULL_REQUEST_TEMPLATE.md │ │ ├── README.md │ │ ├── appengine.go │ │ ├── buffer.go │ │ ├── collations.go │ │ ├── connection.go │ │ ├── const.go │ │ ├── driver.go │ │ ├── dsn.go │ │ ├── errors.go │ │ ├── infile.go │ │ ├── packets.go │ │ ├── result.go │ │ ├── rows.go │ │ ├── statement.go │ │ ├── transaction.go │ │ └── utils.go ├── golang │ ├── glog │ │ ├── LICENSE │ │ ├── README │ │ ├── glog.go │ │ └── glog_file.go │ └── protobuf │ │ ├── LICENSE │ │ └── proto │ │ ├── Makefile │ │ ├── clone.go │ │ ├── decode.go │ │ ├── encode.go │ │ ├── equal.go │ │ ├── extensions.go │ │ ├── lib.go │ │ ├── message_set.go │ │ ├── pointer_reflect.go │ │ ├── pointer_unsafe.go │ │ ├── properties.go │ │ ├── text.go │ │ └── text_parser.go ├── gorilla │ ├── context │ │ ├── LICENSE │ │ ├── README.md │ │ ├── context.go │ │ └── doc.go │ ├── mux │ │ ├── LICENSE │ │ ├── README.md │ │ ├── context_gorilla.go │ │ ├── context_native.go │ │ ├── doc.go │ │ ├── mux.go │ │ ├── regexp.go │ │ └── route.go │ ├── securecookie │ │ ├── LICENSE │ │ ├── README.md │ │ ├── doc.go │ │ ├── fuzz.go │ │ └── securecookie.go │ └── sessions │ │ ├── LICENSE │ │ ├── README.md │ │ ├── doc.go │ │ ├── lex.go │ │ ├── sessions.go │ │ └── store.go └── imdario │ └── mergo │ ├── LICENSE │ ├── README.md │ ├── doc.go │ ├── map.go │ ├── merge.go │ └── mergo.go ├── golang.org └── x │ └── net │ ├── LICENSE │ ├── PATENTS │ ├── context │ ├── context.go │ ├── go17.go │ └── pre_go17.go │ └── html │ ├── atom │ ├── atom.go │ ├── atom_test.go │ ├── gen.go │ ├── table.go │ └── table_test.go │ ├── charset │ ├── charset.go │ ├── charset_test.go │ └── testdata │ │ ├── HTTP-charset.html │ │ ├── HTTP-vs-UTF-8-BOM.html │ │ ├── HTTP-vs-meta-charset.html │ │ ├── HTTP-vs-meta-content.html │ │ ├── No-encoding-declaration.html │ │ ├── README │ │ ├── UTF-16BE-BOM.html │ │ ├── UTF-16LE-BOM.html │ │ ├── UTF-8-BOM-vs-meta-charset.html │ │ ├── UTF-8-BOM-vs-meta-content.html │ │ ├── meta-charset-attribute.html │ │ └── meta-content-attribute.html │ ├── const.go │ ├── doc.go │ ├── doctype.go │ ├── entity.go │ ├── entity_test.go │ ├── escape.go │ ├── escape_test.go │ ├── example_test.go │ ├── foreign.go │ ├── node.go │ ├── node_test.go │ ├── parse.go │ ├── parse_test.go │ ├── render.go │ ├── render_test.go │ ├── testdata │ ├── go1.html │ └── webkit │ │ ├── README │ │ ├── adoption01.dat │ │ ├── adoption02.dat │ │ ├── comments01.dat │ │ ├── doctype01.dat │ │ ├── entities01.dat │ │ ├── entities02.dat │ │ ├── html5test-com.dat │ │ ├── inbody01.dat │ │ ├── isindex.dat │ │ ├── pending-spec-changes-plain-text-unsafe.dat │ │ ├── pending-spec-changes.dat │ │ ├── plain-text-unsafe.dat │ │ ├── scriptdata01.dat │ │ ├── scripted │ │ ├── adoption01.dat │ │ └── webkit01.dat │ │ ├── tables01.dat │ │ ├── tests1.dat │ │ ├── tests10.dat │ │ ├── tests11.dat │ │ ├── tests12.dat │ │ ├── tests14.dat │ │ ├── tests15.dat │ │ ├── tests16.dat │ │ ├── tests17.dat │ │ ├── tests18.dat │ │ ├── tests19.dat │ │ ├── tests2.dat │ │ ├── tests20.dat │ │ ├── tests21.dat │ │ ├── tests22.dat │ │ ├── tests23.dat │ │ ├── tests24.dat │ │ ├── tests25.dat │ │ ├── tests26.dat │ │ ├── tests3.dat │ │ ├── tests4.dat │ │ ├── tests5.dat │ │ ├── tests6.dat │ │ ├── tests7.dat │ │ ├── tests8.dat │ │ ├── tests9.dat │ │ ├── tests_innerHTML_1.dat │ │ ├── tricky01.dat │ │ ├── webkit01.dat │ │ └── webkit02.dat │ ├── token.go │ └── token_test.go ├── google.golang.org └── appengine │ ├── LICENSE │ ├── README.md │ ├── appengine.go │ ├── appengine_vm.go │ ├── cloudsql │ ├── cloudsql.go │ ├── cloudsql_classic.go │ └── cloudsql_vm.go │ ├── errors.go │ ├── identity.go │ ├── internal │ ├── api.go │ ├── api_classic.go │ ├── api_common.go │ ├── app_id.go │ ├── app_identity │ │ ├── app_identity_service.pb.go │ │ └── app_identity_service.proto │ ├── base │ │ ├── api_base.pb.go │ │ └── api_base.proto │ ├── datastore │ │ ├── datastore_v3.pb.go │ │ └── datastore_v3.proto │ ├── identity.go │ ├── identity_classic.go │ ├── identity_vm.go │ ├── internal.go │ ├── log │ │ ├── log_service.pb.go │ │ └── log_service.proto │ ├── mail │ │ ├── mail_service.pb.go │ │ └── mail_service.proto │ ├── metadata.go │ ├── modules │ │ ├── modules_service.pb.go │ │ └── modules_service.proto │ ├── net.go │ ├── regen.sh │ ├── remote_api │ │ ├── remote_api.pb.go │ │ └── remote_api.proto │ ├── socket │ │ ├── socket_service.pb.go │ │ └── socket_service.proto │ ├── taskqueue │ │ ├── taskqueue_service.pb.go │ │ └── taskqueue_service.proto │ ├── transaction.go │ └── urlfetch │ │ ├── urlfetch_service.pb.go │ │ └── urlfetch_service.proto │ ├── log │ ├── api.go │ └── log.go │ ├── mail │ └── mail.go │ ├── namespace.go │ ├── socket │ ├── doc.go │ ├── socket_classic.go │ └── socket_vm.go │ ├── taskqueue │ └── taskqueue.go │ ├── timeout.go │ └── urlfetch │ └── urlfetch.go ├── gopkg.in └── yaml.v2 │ ├── LICENSE │ ├── LICENSE.libyaml │ ├── README.md │ ├── apic.go │ ├── decode.go │ ├── emitterc.go │ ├── encode.go │ ├── parserc.go │ ├── readerc.go │ ├── resolve.go │ ├── scannerc.go │ ├── sorter.go │ ├── writerc.go │ ├── yaml.go │ ├── yamlh.go │ └── yamlprivateh.go └── vendor.json /.gitignore: -------------------------------------------------------------------------------- 1 | \*scratch* 2 | [#]*[#] 3 | .#* 4 | *~ 5 | .gcloud/* 6 | */*/config.yaml 7 | *.pyc 8 | *.log* 9 | .DS_Store 10 | /prober 11 | /xelaiemon 12 | *.cp 13 | *.swp 14 | *.css.map 15 | .sass-cache 16 | /bower_components 17 | /node_modules 18 | /.sass-cache 19 | 20 | # (Alexei) I created some sym-links from site directory to static directory for myself 21 | src/site/html 22 | src/site/js 23 | src/site/scss 24 | db1 25 | 26 | bundle.js 27 | src/site/static/js/typings/ 28 | 29 | .last_deps_update 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/machine-intelligence/arbital-open-source/ce5ee1c472e39834fbd61b895ba23b501aa96e54/README.md -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arbital", 3 | "version": "0.0.0", 4 | "private": true, 5 | "dependencies": { 6 | "jquery": "~2.2.0", 7 | "angular": "~1.4.8", 8 | "angular-mocks": "~1.4.8", 9 | "angular-route": "~1.4.8", 10 | "MathJax": "~2.6.0", 11 | "angular-animate": "~1.4.8", 12 | "angular-aria": "~1.4.8", 13 | "angular-material": "~1.0.2", 14 | "angular-messages": "~1.4.8", 15 | "angular-recursion": "~1.0.5", 16 | "angular-resource": "~1.4.8", 17 | "angular-sanitize": "~1.4.8" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.0.0", 3 | "private": true, 4 | "name": "arbital", 5 | "devDependencies": { 6 | "fsevents": "^1.0.17" 7 | }, 8 | "scripts": { 9 | "postinstall": "cd src/site/static/js && typings install", 10 | "typings": "cd src/site/static/js && typings", 11 | "webpack": "cd src/site/webpack && webpack", 12 | "webpack-dev-server": "cd src/site/webpack && webpack-dev-server", 13 | "prestart": "npm install", 14 | "start": "scripts/stage.sh" 15 | }, 16 | "dependencies": { 17 | "css-loader": "^0.23.1", 18 | "deepmerge": "^0.2.10", 19 | "diff-match-patch": "^1.0.0", 20 | "html-loader": "^0.4.3", 21 | "loader-utils": "^0.2.15", 22 | "ngtemplate-loader": "^1.3.1", 23 | "node-sass": "^3.8.0", 24 | "sass-loader": "^4.0.0", 25 | "source-map-loader": "^0.1.5", 26 | "style-loader": "^0.13.1", 27 | "ts-loader": "^0.8.2", 28 | "typescript": "^1.8.10", 29 | "typings": "^1.3.2", 30 | "webpack": "^1.13.1", 31 | "webpack-dev-server": "^1.14.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /schemas/aliasRedirects.sql: -------------------------------------------------------------------------------- 1 | /* When a page's alias is changed, we add a row in this table. */ 2 | CREATE TABLE aliasRedirects ( 3 | 4 | /* The old alias. */ 5 | oldAlias VARCHAR(64) NOT NULL, 6 | 7 | /* The new alias. */ 8 | newAlias VARCHAR(64) NOT NULL, 9 | 10 | UNIQUE(oldAlias) 11 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 12 | -------------------------------------------------------------------------------- /schemas/anchors.sql: -------------------------------------------------------------------------------- 1 | /* TODO: we are not actually using this table ATM, but probably should. */ 2 | /* This table contains all the anchors. An anchor determines a specific place 3 | inside a page, including the paragraph and the specific text within it. */ 4 | CREATE TABLE anchors ( 5 | /* Id of this anchor. */ 6 | id BIGINT NOT NULL AUTO_INCREMENT, 7 | /* Text of the paragraph the anchor is in. */ 8 | paragraph MEDIUMTEXT NOT NULL, 9 | /* Text within the paragraph. If empty, assume it's attached to the entire 10 | pararaph. */ 11 | text MEDIUMTEXT NOT NULL, 12 | /* Offset of the text inside the paragraph. */ 13 | offset INT NOT NULL, 14 | /* When this was created. */ 15 | createdAt DATETIME NOT NULL, 16 | 17 | PRIMARY KEY(id) 18 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 19 | -------------------------------------------------------------------------------- /schemas/answers.sql: -------------------------------------------------------------------------------- 1 | /* A row for every answer. An answer is a pointer to another page, and it's always 2 | attached to a question. */ 3 | CREATE TABLE answers ( 4 | /* Id of this answer. */ 5 | id BIGINT NOT NULL AUTO_INCREMENT, 6 | /* Id of the question this answer is for. FK into pages. */ 7 | questionId VARCHAR(32) NOT NULL, 8 | /* Id of the user who added this string. FK into users. */ 9 | answerPageId VARCHAR(32) NOT NULL, 10 | /* Id of the user who added this answer. FK into users. */ 11 | userId VARCHAR(32) NOT NULL, 12 | /* Date this answer was created. */ 13 | createdAt DATETIME NOT NULL, 14 | PRIMARY KEY(id) 15 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 16 | -------------------------------------------------------------------------------- /schemas/changeLogs.sql: -------------------------------------------------------------------------------- 1 | /* This table contains an entry for every change that a page undergoes. */ 2 | CREATE TABLE changeLogs ( 3 | 4 | /* Unique update id. PK. */ 5 | id BIGINT NOT NULL AUTO_INCREMENT, 6 | 7 | /* Likeable id for this changelog. Partial FK into likes. 8 | Note that this is not set until the first time this changelog is liked. */ 9 | likeableId BIGINT NOT NULL, 10 | 11 | /* The user who caused this event. FK into users. */ 12 | userId VARCHAR(32) NOT NULL, 13 | 14 | /* The affected page. FK into pages. */ 15 | pageId VARCHAR(32) NOT NULL, 16 | 17 | /* Optional edit number of the affected page. Partial FK into pages. */ 18 | edit INT NOT NULL, 19 | 20 | /* Type of update */ 21 | type VARCHAR(32) NOT NULL, 22 | 23 | /* When this update was created. */ 24 | createdAt DATETIME NOT NULL, 25 | 26 | /* This is set for various events. E.g. if a new parent is added, this will 27 | be set to the parent id. */ 28 | auxPageId VARCHAR(32) NOT NULL, 29 | 30 | /* So that we can show what changed in the change log. */ 31 | oldSettingsValue VARCHAR(1024) NOT NULL, 32 | newSettingsValue VARCHAR(1024) NOT NULL, 33 | 34 | PRIMARY KEY(id) 35 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 36 | -------------------------------------------------------------------------------- /schemas/contentRequests.sql: -------------------------------------------------------------------------------- 1 | /* An entry for every content request pair (page and type) */ 2 | CREATE TABLE contentRequests ( 3 | 4 | /* Id of the request. */ 5 | id BIGINT NOT NULL AUTO_INCREMENT, 6 | 7 | /* The page the request was made for. FK into pages. */ 8 | pageId VARCHAR(32) NOT NULL, 9 | 10 | /* Type of request. E.g. slowDown, speedUp, etc. */ 11 | type VARCHAR(32) NOT NULL, 12 | 13 | /* Id by which we track likes. FK into likes. */ 14 | likeableId BIGINT NOT NULL, 15 | 16 | /* Date this entry was created. */ 17 | createdAt DATETIME NOT NULL, 18 | 19 | /* There can only be one row per (page, type) pair */ 20 | UNIQUE KEY(pageId,type), 21 | 22 | PRIMARY KEY(id) 23 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 24 | -------------------------------------------------------------------------------- /schemas/discussionSubscriptions.sql: -------------------------------------------------------------------------------- 1 | /* This table contains all the subscriptions to discussions (page or comments). */ 2 | CREATE TABLE discussionSubscriptions ( 3 | 4 | /* User id of the subscriber. FK into users. */ 5 | userId VARCHAR(32) NOT NULL, 6 | 7 | /* Id of page/comment the user is subscribed to. FK into pageInfos. */ 8 | toPageId VARCHAR(32) NOT NULL, 9 | 10 | /* When this subscription was created. */ 11 | createdAt DATETIME NOT NULL, 12 | 13 | PRIMARY KEY(userId, toPageId) 14 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 15 | -------------------------------------------------------------------------------- /schemas/domainFriends.sql: -------------------------------------------------------------------------------- 1 | /* This table contains all domain pairs that are friendly with each other. */ 2 | CREATE TABLE domainFriends ( 3 | /* Domain id. FK into domains. */ 4 | domainId BIGINT NOT NULL, 5 | /* Id of another domain this domain is friends with. FK into domains. */ 6 | friendId BIGINT NOT NULL, 7 | /* When this friendship was originally created. */ 8 | createdAt DATETIME NOT NULL, 9 | /* Id of the user who created the friendship. FK into users. */ 10 | createdBy VARCHAR(32) NOT NULL, 11 | 12 | UNIQUE(domainId,friendId) 13 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 14 | -------------------------------------------------------------------------------- /schemas/domainMembers.sql: -------------------------------------------------------------------------------- 1 | /* An entry for every member in a domain. */ 2 | CREATE TABLE domainMembers ( 3 | 4 | /* Id of the domain. FK into domains. */ 5 | domainId BIGINT NOT NULL, 6 | 7 | /* Id of the user member. FK into users. */ 8 | userId VARCHAR(32) NOT NULL, 9 | 10 | /* Date this user was added. */ 11 | createdAt DATETIME NOT NULL, 12 | 13 | /* User's role in this domain. */ 14 | role VARCHAR(32) NOT NULL, 15 | 16 | PRIMARY KEY(domainId,userId) 17 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 18 | -------------------------------------------------------------------------------- /schemas/domains.sql: -------------------------------------------------------------------------------- 1 | /* This table contains all domains and relevant info. */ 2 | CREATE TABLE domains ( 3 | /* Domain id. */ 4 | id BIGINT NOT NULL AUTO_INCREMENT, 5 | /* Id of the home page for this domain. FK into pageInfos. */ 6 | pageId VARCHAR(32) NOT NULL, 7 | /* When this page was originally created. */ 8 | createdAt DATETIME NOT NULL, 9 | /* Id of the user who created the page. FK into users. */ 10 | createdBy VARCHAR(32) NOT NULL, 11 | /* Alias name of the domain. */ 12 | alias VARCHAR(64) NOT NULL, 13 | 14 | /* ============ Various domain settings ============ */ 15 | /* If true, any registered user can comment. */ 16 | canUsersComment BOOL NOT NULL, 17 | /* If true, any registered user can propose a comment. */ 18 | canUsersProposeComment BOOL NOT NULL, 19 | /* If true, any registered user can propose an edit. */ 20 | canUsersProposeEdits BOOL NOT NULL, 21 | 22 | PRIMARY KEY(id) 23 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 24 | -------------------------------------------------------------------------------- /schemas/feedPages.sql: -------------------------------------------------------------------------------- 1 | /* This table contains all the feed pages. */ 2 | CREATE TABLE feedPages ( 3 | 4 | /* Id of the domain feed. FK into domains. */ 5 | domainId BIGINT NOT NULL, 6 | 7 | /* Id of the page in the feed. FK into pageInfos. */ 8 | pageId VARCHAR(32) NOT NULL, 9 | 10 | /* Id of the user who submitted it to the feed. FK into users. */ 11 | submitterId VARCHAR(32) NOT NULL, 12 | 13 | /* When this submission was made. */ 14 | createdAt DATETIME NOT NULL, 15 | 16 | /* Score for this feed page, determining where it appears in the feed. */ 17 | score DOUBLE NOT NULL, 18 | 19 | PRIMARY KEY(domainId, pageId) 20 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 21 | -------------------------------------------------------------------------------- /schemas/invites.sql: -------------------------------------------------------------------------------- 1 | /* An entry for every invite. */ 2 | CREATE TABLE invites ( 3 | /* Id of user sending invite. FK into users. */ 4 | fromUserId VARCHAR(32) NOT NULL, 5 | /* Id of domain that this invite is for. FK into domains. */ 6 | domainId BIGINT NOT NULL, 7 | /* Role the invited user will receive. */ 8 | role VARCHAR(32) NOT NULL, 9 | /* Email address to send invite to. */ 10 | toEmail VARCHAR(100) NOT NULL, 11 | /* Date this invite was created. */ 12 | createdAt DATETIME NOT NULL, 13 | /* If a user claimed this invite, this is their id. FK into users. */ 14 | toUserId VARCHAR(32) NOT NULL, 15 | /* Date this invite was claimed */ 16 | claimedAt DATETIME NOT NULL, 17 | /* When the invite email was sent. */ 18 | emailSentAt DATETIME NOT NULL, 19 | 20 | PRIMARY KEY(fromUserId,domainId,toEmail) 21 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 22 | -------------------------------------------------------------------------------- /schemas/lastViews.sql: -------------------------------------------------------------------------------- 1 | /* A table for keeping track of the last time the user saw various things */ 2 | CREATE TABLE lastViews ( 3 | /* Id of the user who viewed the thing. */ 4 | userId varchar(32) NOT NULL, 5 | /* The thing the user viewed. */ 6 | viewName varchar(64) NOT NULL, 7 | /* The last time the user viewed the thing. */ 8 | viewedAt DATETIME NOT NULL, 9 | 10 | PRIMARY KEY(userId,viewName) 11 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 12 | -------------------------------------------------------------------------------- /schemas/lastVisits.sql: -------------------------------------------------------------------------------- 1 | /* Each row is a page-user pair with the date and time when the user has last seen the page. */ 2 | CREATE TABLE lastVisits ( 3 | 4 | /* FK into users. */ 5 | userId VARCHAR(64) NOT NULL, 6 | 7 | /* Page id. FK into pages. */ 8 | pageId VARCHAR(32) NOT NULL, 9 | 10 | /* Date of the first visit. */ 11 | createdAt DATETIME NOT NULL, 12 | 13 | /* Date of the last visit. */ 14 | updatedAt DATETIME NOT NULL, 15 | 16 | UNIQUE(userId,pageId) 17 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 18 | -------------------------------------------------------------------------------- /schemas/lenses.sql: -------------------------------------------------------------------------------- 1 | /* This table contains all information about lens relationships. */ 2 | CREATE TABLE lenses ( 3 | /* Id of the lens relationships. */ 4 | id BIGINT NOT NULL AUTO_INCREMENT, 5 | /* Id of the page that has the lens. FK into pageInfos. */ 6 | pageId VARCHAR(32) NOT NULL, 7 | /* Id of the lens page. FK into pageInfos. */ 8 | lensId VARCHAR(32) NOT NULL, 9 | /* Ordering index when sorting the page's lenses. */ 10 | lensIndex INT NOT NULL, 11 | /* Lens name that shows up in the tab. */ 12 | lensName VARCHAR(32) NOT NULL, 13 | /* Lens subtitle that shows up in the tab. */ 14 | lensSubtitle VARCHAR(256) NOT NULL, 15 | /* Id of the user who created the relationship. FK into users. */ 16 | createdBy VARCHAR(32) NOT NULL, 17 | /* When this lens relationship was originally created. */ 18 | createdAt DATETIME NOT NULL, 19 | /* Id of the last user who updated the relationship. FK into users. */ 20 | updatedBy VARCHAR(32) NOT NULL, 21 | /* When this relationship was updated last. */ 22 | updatedAt DATETIME NOT NULL, 23 | 24 | UNIQUE(lensId), 25 | /* This constraint should apply, but makes it very difficult to update the lensIndex for multiple rows */ 26 | /*UNIQUE(pageId,lensIndex),*/ 27 | PRIMARY KEY(id) 28 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 29 | -------------------------------------------------------------------------------- /schemas/likeableIds.sql: -------------------------------------------------------------------------------- 1 | /* A table for keeping track of likeableIds */ 2 | CREATE TABLE likeableIds ( 3 | /* Id of the likeable. */ 4 | id BIGINT NOT NULL AUTO_INCREMENT, 5 | PRIMARY KEY(id) 6 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 7 | -------------------------------------------------------------------------------- /schemas/likes.sql: -------------------------------------------------------------------------------- 1 | /* An entry for every like a user cast for a likeable object, such as a page 2 | or changelog. */ 3 | CREATE TABLE likes ( 4 | /* Id of the user who liked. FK into users. */ 5 | userId VARCHAR(32) NOT NULL, 6 | 7 | /* Id of the likeable this like is for. */ 8 | likeableId BIGINT NOT NULL, 9 | 10 | /* User's trust when they made the like. FK into userTrustSnapshots */ 11 | userTrustSnapshotId BIGINT NOT NULL, 12 | 13 | /* Like value [-1,1]. */ 14 | value TINYINT NOT NULL, 15 | 16 | /* Date this like was created. */ 17 | createdAt DATETIME NOT NULL, 18 | 19 | /* Date this like was updated. */ 20 | updatedAt DATETIME NOT NULL, 21 | 22 | PRIMARY KEY(userId,likeableId) 23 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 24 | -------------------------------------------------------------------------------- /schemas/links.sql: -------------------------------------------------------------------------------- 1 | /* When a parent page has a link to a child page, we add a row in this table. */ 2 | CREATE TABLE links ( 3 | 4 | /* Id of the parent page. FK into pages. */ 5 | parentId VARCHAR(32) NOT NULL, 6 | 7 | /* Alias or id of the child claim. */ 8 | childAlias VARCHAR(64) NOT NULL, 9 | 10 | UNIQUE(parentId, childAlias) 11 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 12 | -------------------------------------------------------------------------------- /schemas/maintainerSubscriptions.sql: -------------------------------------------------------------------------------- 1 | /* This table contains all the maintainance subscriptions. */ 2 | CREATE TABLE maintainerSubscriptions ( 3 | 4 | /* User id of the subscriber. FK into users. */ 5 | userId VARCHAR(32) NOT NULL, 6 | 7 | /* Id of the page the user is subscribed to. FK into pageInfos. */ 8 | toPageId VARCHAR(32) NOT NULL, 9 | 10 | /* When this subscription was created. */ 11 | createdAt DATETIME NOT NULL, 12 | 13 | PRIMARY KEY(userId, toPageId) 14 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 15 | -------------------------------------------------------------------------------- /schemas/pageSummaries.sql: -------------------------------------------------------------------------------- 1 | /* This table contains all the summaries for all the pages. */ 2 | CREATE TABLE pageSummaries ( 3 | 4 | /* Id of the page the summary is for. */ 5 | pageId VARCHAR(32) NOT NULL, 6 | 7 | /* Name of the summary. */ 8 | name VARCHAR(32) NOT NULL, 9 | 10 | /* Text of the summary. */ 11 | text TEXT NOT NULL, 12 | 13 | PRIMARY KEY(pageId, name) 14 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 15 | 16 | -------------------------------------------------------------------------------- /schemas/pageToDomainSubmissions.sql: -------------------------------------------------------------------------------- 1 | /* This table contains pages that have been submitted to a domain. */ 2 | CREATE TABLE pageToDomainSubmissions ( 3 | /* Id of the submitted page. FK into pageInfos. */ 4 | pageId VARCHAR(32) NOT NULL, 5 | /* Id of the domain it's submitted to. FK into pageInfos. */ 6 | domainId VARCHAR(32) NOT NULL, 7 | /* When this submission was originally created. */ 8 | createdAt DATETIME NOT NULL, 9 | /* Id of the user who submitted. FK into users. */ 10 | submitterId VARCHAR(32) NOT NULL, 11 | 12 | /* When this submission was approved. */ 13 | approvedAt DATETIME NOT NULL, 14 | /* Id of the user who approved the submission. FK into users. */ 15 | approverId VARCHAR(32) NOT NULL, 16 | 17 | PRIMARY KEY(pageId,domainId) 18 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 19 | -------------------------------------------------------------------------------- /schemas/pathInstances.sql: -------------------------------------------------------------------------------- 1 | /* This table contains a row for each path a user has started. */ 2 | CREATE TABLE pathInstances ( 3 | /* Id of this entry. */ 4 | id BIGINT NOT NULL AUTO_INCREMENT, 5 | /* User who started this path. FK into users. */ 6 | userId VARCHAR(32) NOT NULL, 7 | /* Id of the page guide that started this path. FK into pageInfos. */ 8 | guideId VARCHAR(32) NOT NULL, 9 | /* Comma separated list of page ids which this path has. FK into pageInfos. */ 10 | pageIds TEXT NOT NULL, 11 | /* Comma separated list of which page added the corresponding page to pageIds. FK into pageInfos. */ 12 | sourcePageIds TEXT NOT NULL, 13 | /* Index of the page the user is on. */ 14 | progress INT NOT NULL, 15 | /* When this instance was created. */ 16 | createdAt DATETIME NOT NULL, 17 | /* When this instance was updated last. */ 18 | updatedAt DATETIME NOT NULL, 19 | /* Optional. If set, the user copied the path from this instance. */ 20 | originalInstanceId BIGINT NOT NULL, 21 | /* Set to true when the user finished the path. */ 22 | isFinished BOOLEAN NOT NULL, 23 | 24 | PRIMARY KEY(id) 25 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 26 | -------------------------------------------------------------------------------- /schemas/pathPages.sql: -------------------------------------------------------------------------------- 1 | /* This table contains what pages belong to which paths. */ 2 | CREATE TABLE pathPages ( 3 | /* Id of this entry. */ 4 | id BIGINT NOT NULL AUTO_INCREMENT, 5 | /* Id of the page guide that starts this path. FK into pageInfos. */ 6 | guideId VARCHAR(32) NOT NULL, 7 | /* Id of one of the pages on the path. FK into pageInfos. */ 8 | pathPageId VARCHAR(32) NOT NULL, 9 | /* Ordering index when ordering the pages in a path. */ 10 | pathIndex INT NOT NULL, 11 | /* Id of the user who created the relationship. FK into users. */ 12 | createdBy VARCHAR(32) NOT NULL, 13 | /* When this lens relationship was originally created. */ 14 | createdAt DATETIME NOT NULL, 15 | /* Id of the last user who updated the relationship. FK into users. */ 16 | updatedBy VARCHAR(32) NOT NULL, 17 | /* When this relationship was updated last. */ 18 | updatedAt DATETIME NOT NULL, 19 | 20 | /* This constraint should apply, but makes it very difficult to update the index for multiple rows */ 21 | /* UNIQUE(guideId,index),*/ 22 | PRIMARY KEY(id) 23 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 24 | -------------------------------------------------------------------------------- /schemas/projects.sql: -------------------------------------------------------------------------------- 1 | /* An entry for every project we have */ 2 | CREATE TABLE projects ( 3 | /* Project id. */ 4 | id BIGINT NOT NULL AUTO_INCREMENT, 5 | 6 | /* The page which describes this project. FK into pages. */ 7 | projectPageId VARCHAR(32) NOT NULL, 8 | 9 | /* The first page the reader should go to. FK into pages. */ 10 | startPageId VARCHAR(32) NOT NULL, 11 | 12 | /* State of the project. "finished", "inProgress", or "requested" */ 13 | state VARCHAR(32) NOT NULL, 14 | 15 | /* Id by which we track who wants to read this. FK into likes. */ 16 | readLikeableId BIGINT NOT NULL, 17 | 18 | /* Id by which we track who wants to write this. FK into likes. */ 19 | writeLikeableId BIGINT NOT NULL, 20 | 21 | /* Date this entry was created. */ 22 | createdAt DATETIME NOT NULL, 23 | 24 | PRIMARY KEY(id) 25 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 26 | -------------------------------------------------------------------------------- /schemas/redLinks.sql: -------------------------------------------------------------------------------- 1 | /* An entry for every red link. */ 2 | CREATE TABLE redLinks ( 3 | /* Alias of the red link. */ 4 | alias VARCHAR(64) NOT NULL, 5 | 6 | /* Id by which we track likes. Partial FK into likes. */ 7 | likeableId BIGINT NOT NULL, 8 | 9 | /* Date this entry was created. */ 10 | createdAt DATETIME NOT NULL, 11 | 12 | PRIMARY KEY(alias) 13 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 14 | -------------------------------------------------------------------------------- /schemas/searchStrings.sql: -------------------------------------------------------------------------------- 1 | /* An entry for every search string that's attached to a page. */ 2 | CREATE TABLE searchStrings ( 3 | /* Id of this search string. */ 4 | id BIGINT NOT NULL AUTO_INCREMENT, 5 | /* Id of the page this string is for. FK into pages. */ 6 | pageId VARCHAR(32) NOT NULL, 7 | /* Id of the user who added this string. FK into users. */ 8 | userId VARCHAR(32) NOT NULL, 9 | /* String's text. */ 10 | text VARCHAR(1024) NOT NULL, 11 | /* Date this string was created. */ 12 | createdAt DATETIME NOT NULL, 13 | PRIMARY KEY(id) 14 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 15 | -------------------------------------------------------------------------------- /schemas/userMasteryPairs.sql: -------------------------------------------------------------------------------- 1 | /* An entry for every mastery a user knows. */ 2 | CREATE TABLE userMasteryPairs ( 3 | 4 | /* Id of the user. FK into users. */ 5 | userId VARCHAR(32) NOT NULL, 6 | 7 | /* Id of the mastery. FK into pages. */ 8 | masteryId VARCHAR(32) NOT NULL, 9 | 10 | /* Date this entry was created. */ 11 | createdAt DATETIME NOT NULL, 12 | 13 | /* Date this entry was updated. */ 14 | updatedAt DATETIME NOT NULL, 15 | 16 | /* Set if the user has this mastery. */ 17 | has BOOLEAN NOT NULL, 18 | 19 | /* Set if the user wants to read this. */ 20 | wants BOOLEAN NOT NULL, 21 | 22 | /* Level of understanding. */ 23 | level INT NOT NULL, 24 | 25 | /* Id of the page where the user marked the mastery learned */ 26 | taughtBy VARCHAR(32) NOT NULL, 27 | 28 | /* User's trust when they learned the mastery. FK into userTrustSnapshots */ 29 | trustSnapshotId BIGINT NOT NULL, 30 | 31 | PRIMARY KEY(userId,masteryId) 32 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 33 | -------------------------------------------------------------------------------- /schemas/userPageObjectPairs.sql: -------------------------------------------------------------------------------- 1 | /* This table contains an entry for each (user, page object) pair, where 2 | the object can store some user specific data. For example, multiple choice 3 | questions can store the user's answer. */ 4 | CREATE TABLE userPageObjectPairs ( 5 | 6 | /* Id of the user the user is for. FK into users. */ 7 | userId VARCHAR(32) NOT NULL, 8 | 9 | /* Id of the page the info is for. */ 10 | pageId VARCHAR(32) NOT NULL, 11 | 12 | /* Page's published edit at the time this value was set. */ 13 | edit INT NOT NULL, 14 | 15 | /* Alias name of the object. */ 16 | object VARCHAR(64) NOT NULL, 17 | 18 | /* When this value was originally created at. */ 19 | createdAt DATETIME NOT NULL, 20 | 21 | /* When this value was updated. */ 22 | updatedAt DATETIME NOT NULL, 23 | 24 | /* Whatever value the object decides to set here. */ 25 | value VARCHAR(512) NOT NULL, 26 | 27 | PRIMARY KEY(userId,pageId,object) 28 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 29 | -------------------------------------------------------------------------------- /schemas/userRequisitePairSnapshots.sql: -------------------------------------------------------------------------------- 1 | /* When we snapshot all user's requisites, we store them in this table. Each snapshot 2 | has the same id, but takes up multiple rows. */ 3 | CREATE TABLE userRequisitePairSnapshots ( 4 | /* Id of the snapshot. Note that this is not unique per row. */ 5 | id BIGINT NOT NULL, 6 | /* Id of the user. FK into users. */ 7 | userId VARCHAR(32) NOT NULL, 8 | /* Id of the requisite. FK into pages. */ 9 | requisiteId VARCHAR(32) NOT NULL, 10 | /* Date this entry was created. */ 11 | createdAt DATETIME NOT NULL, 12 | /* Set if the user has this mastery. */ 13 | has BOOLEAN NOT NULL, 14 | /* Set if the user wants to read this. */ 15 | wants BOOLEAN NOT NULL 16 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 17 | -------------------------------------------------------------------------------- /schemas/userSubscriptions.sql: -------------------------------------------------------------------------------- 1 | /* This table contains all the subscriptions to users. */ 2 | CREATE TABLE userSubscriptions ( 3 | 4 | /* User id of the subscriber. FK into users. */ 5 | userId VARCHAR(32) NOT NULL, 6 | 7 | /* Id of the user this user is subscribed to. FK into users. */ 8 | toUserId VARCHAR(32) NOT NULL, 9 | 10 | /* When this subscription was created. */ 11 | createdAt DATETIME NOT NULL, 12 | 13 | PRIMARY KEY(userId, toUserId) 14 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 15 | -------------------------------------------------------------------------------- /schemas/visits.sql: -------------------------------------------------------------------------------- 1 | /* Each row is a page-user pair with the date and time 2 | when the user has last seen the page. */ 3 | CREATE TABLE visits ( 4 | 5 | /* If the user is logged in, user's id. FK into users. */ 6 | userId VARCHAR(64) NOT NULL, 7 | 8 | /* Session id. If the user is *not* logged in, the userId will be the same as this value. */ 9 | sessionId VARCHAR(64) NOT NULL, 10 | 11 | /* Analytics id. Base64-encoded Sha256 hash of the session id. */ 12 | analyticsId VARCHAR(64) NOT NULL, 13 | 14 | /* IP address of the user's computer. */ 15 | ipAddress VARCHAR(64) NOT NULL, 16 | 17 | /* Page id. FK into pages. */ 18 | pageId VARCHAR(32) NOT NULL, 19 | 20 | /* When this visit occured. */ 21 | createdAt DATETIME NOT NULL 22 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 23 | -------------------------------------------------------------------------------- /schemas/votes.sql: -------------------------------------------------------------------------------- 1 | /* An entry for every probability vote a user casts for a question. There could be 2 | multiple votes from one user for the same page. */ 3 | CREATE TABLE votes ( 4 | 5 | /* PK. Vote's unique id. */ 6 | id BIGINT NOT NULL AUTO_INCREMENT, 7 | 8 | /* Id of the user who voted. FK into users. */ 9 | userId VARCHAR(32) NOT NULL, 10 | 11 | /* Id of the page this vote is for. FK into pages. */ 12 | pageId VARCHAR(32) NOT NULL, 13 | 14 | /* Vote value. Special values are: 15 | -1: mu 16 | -2: no vote */ 17 | value TINYINT NOT NULL, 18 | 19 | /* Date this like was created. */ 20 | createdAt DATETIME NOT NULL, 21 | 22 | PRIMARY KEY(id) 23 | ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 24 | -------------------------------------------------------------------------------- /scripts/build_gomon.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Builds the "gomon" Docker image. 4 | # 5 | source init.sh || exit 6 | TARGET=containers/monitoring/ 7 | cp -v scripts/gcloud_bashrc.sh ${TARGET} 8 | cp -v config.yaml ${TARGET} 9 | # cp src/go/monitoring ${TARGET} 10 | sudo docker build -t "hkjn/gomon" ${TARGET} 11 | -------------------------------------------------------------------------------- /scripts/check_deps.go: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env gorun 2 | 3 | package main 4 | 5 | import ( 6 | "log" 7 | "os" 8 | "os/exec" 9 | "path/filepath" 10 | ) 11 | 12 | const depsFile = ".last_deps_update" 13 | 14 | func main() { 15 | log.SetFlags(0) 16 | depsFi, err := os.Stat(depsFile) 17 | if err != nil && !os.IsNotExist(err) { 18 | log.Fatal(err) 19 | } 20 | 21 | newerThan := func(path string) bool { 22 | fi, err := os.Stat(path) 23 | if err != nil { 24 | log.Fatal(err) 25 | } 26 | return depsFi.ModTime().After(fi.ModTime()) 27 | } 28 | 29 | if err == nil && 30 | newerThan("package.json") && 31 | newerThan(filepath.FromSlash("src/site/static/js/typings.json")) { 32 | return 33 | } 34 | 35 | cmd := exec.Command("npm", "install") 36 | cmd.Stdin = os.Stdin 37 | cmd.Stdout = os.Stdout 38 | cmd.Stderr = os.Stderr 39 | if err := cmd.Run(); err != nil { 40 | log.Fatal(err) 41 | } 42 | 43 | if f, err := os.Create(depsFile); err != nil { 44 | log.Printf("Failed to record dependency update. Future runs of stage.sh will start more slowly than necessary. Error from os.Create: %v", err) 45 | } else { 46 | f.Close() 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /scripts/configs_identical.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Utility for checking whether the config.yaml is up to date, i.e. if 4 | # the decrypted config.yaml.pgp equals it in contents. 5 | # 6 | # If it does not, this either means that: 7 | # 1. more changes arrived in config.yaml.pgp since your config.yaml was decrypted 8 | # 2. you've changed config.yaml locally and haven't re-encrypted and 9 | # pushed the changes to config.yaml.pgp 10 | source init.sh || exit 11 | 12 | cp -iv config.yaml config.yaml.bak 13 | echo "Decrypting config.yaml.gpg -> config.yaml.." >&2 14 | decrypt_config.sh 15 | if diff config.yaml.bak config.yaml ; then 16 | echo "Identical." >&2 17 | rm config.yaml.bak 18 | exit 0 19 | else 20 | echo "The config.yaml file differs from your local copy, moved your changes to config.yaml.bak." >&2 21 | echo "Please merge and commit your changes, or remove if they're not needed." >&2 22 | exit 1 23 | fi 24 | -------------------------------------------------------------------------------- /scripts/create_daemon_user.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Sets up 'xelaiedaemon' user, which runs the monitoring 4 | # dashboards. The password needs to be entered interactively (TODO: 5 | # fix this, read from config.yaml), and should be the value in 6 | # config.vm.daemon.password. 7 | # 8 | # This script assumes that the environment on this machine is set up 9 | # correctly for your user, i.e. that you can run stage.sh / 10 | # run_monitoring.sh and everything works. 11 | # 12 | # Note that the xelaiedaemon will be able to authenticate as you to 13 | # gcloud since your credentials are copied over. TODO: use service 14 | # account here if it can be made to work. 15 | 16 | source init.sh || exit 17 | DAEMON=xelaiedaemon 18 | sudo adduser ${DAEMON} 19 | 20 | for t in ".bashrc" "go_appengine" "go" "google-cloud-sdk" "src"; do 21 | sudo cp -vr ~/${t} /home/${DAEMON}/ 22 | sudo chown -vR ${DAEMON}:${DAEMON} /home/${DAEMON}/${t} 23 | done 24 | 25 | -------------------------------------------------------------------------------- /scripts/create_db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Creates xelaie DB and tables on MySQL server at localhost. 4 | 5 | source init.sh || exit 6 | 7 | HOST=localhost 8 | 9 | read -r -p "This script will DROP ALL DB DATA and rebuild the database at ${HOST}. Is this your intent? [y/N] " response 10 | if [[ ! $response =~ ^([yY][eE][sS]|[yY])$ ]]; then 11 | exit 12 | fi 13 | 14 | DB_NAME=$(cfg mysql.database) 15 | DB_USER=$(cfg mysql.user) 16 | ROOT_PW=$(cfg mysql.root.password) 17 | USER_PW=$(cfg mysql.password) 18 | 19 | echo "Creating DB ${DB_NAME}@${HOST}.." 20 | mysql --host ${HOST} -u root -p"${ROOT_PW}" -e "DROP DATABASE IF EXISTS ${DB_NAME}; CREATE DATABASE IF NOT EXISTS ${DB_NAME} DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci; USE ${DB_NAME};" 21 | 22 | echo "Creating user ${DB_USER}.." 23 | # Note that "GRANT" also creates the user, if necessary (no point in using "CREATE USER"): 24 | # http://justcheckingonall.wordpress.com/2011/07/31/create-user-if-not-exists/ 25 | mysql --host ${HOST} -u root -p"${ROOT_PW}" -e "GRANT ALL ON ${DB_NAME}.* TO '${DB_USER}'@'%' IDENTIFIED BY '${USER_PW}';" 26 | 27 | SCHEMAS=schemas/*.sql 28 | for f in $SCHEMAS; do 29 | echo "Importing schema ${f}.." 30 | cat ${f} | mysql --host ${HOST} -u ${DB_USER} -p${USER_PW} ${DB_NAME} 31 | done 32 | 33 | echo "All done." 34 | -------------------------------------------------------------------------------- /scripts/create_monitoring_vm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Creates the monitoring GCE VM from container manifest. 4 | # 5 | source init.sh || exit 6 | 7 | PROJECT_NAME="exemplary-cycle-688" 8 | INSTANCE="monitoring-5" 9 | ZONE="europe-west1-b" 10 | CONTAINER_MANIFEST="containers/monitoring.yaml" 11 | if [ ! -e ${CONTAINER_MANIFEST} ]; then 12 | echo "Missing manifest file ${CONTAINER_MANIFEST}." >&2 13 | exit 1 14 | fi 15 | 16 | # A list of container VM images can be gotten with gcloud compute 17 | # images list --project google-containers, via 18 | # https://cloud.google.com/compute/docs/containers/container_vms. 19 | gcloud compute --project ${PROJECT_NAME} instances create ${INSTANCE} \ 20 | --image "container-vm-v20140929" \ 21 | --image-project "google-containers" \ 22 | --metadata-from-file "google-container-manifest=${CONTAINER_MANIFEST}" \ 23 | --tags "http-server" \ 24 | --zone ${ZONE} \ 25 | --network "staging" \ 26 | --machine-type "f1-micro" \ 27 | --scopes "https://www.googleapis.com/auth/compute" "https://www.googleapis.com/auth/devstorage.read_only" 28 | 29 | echo "Sleeping 60s to allow VM to boot.." >&2 30 | sleep 60 31 | 32 | gcloud_bootstrap_init.sh ${INSTANCE} ${ZONE} 33 | echo "All done." >&2 34 | 35 | -------------------------------------------------------------------------------- /scripts/create_pages.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Updates the tables with the schema changes. 4 | 5 | source init.sh || exit 6 | 7 | HOST=localhost 8 | 9 | DB_NAME=$(cfg mysql.database) 10 | DB_USER=$(cfg mysql.user) 11 | ROOT_PW=$(cfg mysql.root.password) 12 | USER_PW=$(cfg mysql.password) 13 | 14 | cat schemas/helpers/create_reqs.sql | mysql -f --host ${HOST} -u ${DB_USER} -p${USER_PW} ${DB_NAME} 15 | cat schemas/helpers/create_reqs2.sql | mysql -f --host ${HOST} -u ${DB_USER} -p${USER_PW} ${DB_NAME} 16 | 17 | echo "All done." 18 | -------------------------------------------------------------------------------- /scripts/db_shell.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Connects to DB with interactive mysql shell. 4 | # 5 | # CAUTION: The session has the same permissions as the app user. Use 6 | # with caution, especially on live. 7 | 8 | source init.sh || exit 9 | 10 | if [ "$#" -ne 1 ]; then 11 | echo "Usage: $0 [localhost|live]" 12 | exit 13 | fi 14 | 15 | if [ $1 == "localhost" ]; then 16 | HOST=localhost 17 | else 18 | HOST=$(cfg "mysql.${1}.address") 19 | fi 20 | 21 | mysql --host ${HOST} -u $(cfg mysql.user) -p$(cfg mysql.password) $(cfg mysql.database) 22 | -------------------------------------------------------------------------------- /scripts/decrypt_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Decrypts config.yaml from config.yaml.gpg. 4 | 5 | gpg --output config.yaml --decrypt config.yaml.pgp 6 | 7 | chmod 600 config.yaml 8 | -------------------------------------------------------------------------------- /scripts/decrypt_config_remote.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Decrypts local config.yaml.gpg and saves it on remote host. 4 | # 5 | # This script allows your private GPG key to stay on your local 6 | # machine, but to be used to decrypt the config remotely. 7 | # 8 | # TODO: gpg-agent (https://www.gnupg.org/documentation/manuals/gnupg/Invoking-GPG_002dAGENT.html) 9 | # or keychain (http://funtoo.org/Package:Keychain) should be able to 10 | # forward GPG keys, if this can be made to work that might be a 11 | # cleaner setup. 12 | 13 | source init.sh || exit 14 | 15 | if [ "$#" -ne 2 ]; then 16 | echo "Usage: $0 [vm, e.g. 'monitoring'] [remote user]" 17 | exit 18 | fi 19 | 20 | INSTANCE=$(cfg "vm.${1}.instance") 21 | ZONE=$(cfg "vm.${1}.zone") 22 | REMOTE_USER=${2} 23 | FILE="src/xelaie/config.yaml" 24 | CONFIG=/home/${REMOTE_USER}/${FILE} 25 | 26 | echo "Decrypting config.yaml.pgp and copying to ${REMOTE_USER}@${HOST}:${CONFIG}.." 27 | gpg --decrypt config.yaml.pgp | gcloud compute ssh ${INSTANCE} \ 28 | --zone ${ZONE} --command \ 29 | "sudo sh -c 'cat - > ${CONFIG} && sudo chmod 600 ${CONFIG}' && sudo chown ${REMOTE_USER}:${REMOTE_USER} ${CONFIG}" 30 | -------------------------------------------------------------------------------- /scripts/deploy_ae.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copy over the config into the AE app's directory, since it otherwise 4 | # won't be copied over in the deployment. 5 | cp -v config.yaml src/site/ 6 | cp -v config.yaml src/queue_daemon/ 7 | 8 | # Update the queues 9 | #appcfg.py update_queues src/site/ 10 | 11 | npm run webpack -- --config prod.config.js || exit 12 | 13 | # Deploy the app. 14 | goapp deploy \ 15 | src/queue_daemon/module.yaml \ 16 | src/site/app.yaml 17 | -------------------------------------------------------------------------------- /scripts/deploy_queue.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copy over the config into the AE app's directory, since it otherwise 4 | # won't be copied over in the deployment. 5 | cp -v config.yaml src/go/queue_daemon/ 6 | 7 | # Deploy the app. 8 | goapp deploy src/go/queue_daemon/module.yaml 9 | -------------------------------------------------------------------------------- /scripts/encrypt_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Encrypts config.yaml as config.yaml.pgp, decryptable by trusted GPG keys. 4 | # 5 | # Note that your local pgp keyring needs to know about everyone on the 6 | # --recipient line below before you'll be able to use their public 7 | # keys for encryption. Run `gpg --import keys/foo.asc` for the 8 | # relevant key foo.asc that you don't have to import. 9 | 10 | source init.sh || exit 11 | 12 | gpg --output config.yaml.pgp --encrypt --armor --recipient me@hkjn.me --recipient alexei@xelaie.com config.yaml 13 | -------------------------------------------------------------------------------- /scripts/file_watcher.patch: -------------------------------------------------------------------------------- 1 | diff --git a/google/appengine/tools/devappserver2/watcher_common.py b/google/appengine/tools/devappserver2/watcher_common.py 2 | index 6cf7fcd..7104b86 100644 3 | --- a/google/appengine/tools/devappserver2/watcher_common.py 4 | +++ b/google/appengine/tools/devappserver2/watcher_common.py 5 | @@ -21,7 +21,10 @@ 6 | import os 7 | 8 | # A prefix for files and directories that we should not watch at all. 9 | -_IGNORED_PREFIX = '.' 10 | +_IGNORED_PREFIX = ( 11 | + '.', 12 | + 'node_modules', 13 | +) 14 | # File suffixes that should be ignored. 15 | _IGNORED_FILE_SUFFIXES = ( 16 | # Python temporaries 17 | -------------------------------------------------------------------------------- /scripts/gcloud_bootstrap_init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Installs dependencies on a GCE VM to act as a monitoring host for 4 | # xelaie. 5 | # 6 | # This script copies over and executes gcloud_bootstrap.sh on the 7 | # remote VM. 8 | # 9 | # Prerequisites: 10 | # 0. gcloud SDK is installed locally. 11 | # 1. SSH agent has unlocked keys to the VM, so passwordless SSH is possible 12 | # (`ssh-add ~/.ssh/google_compute_engine or similar). 13 | 14 | source init.sh || exit 15 | 16 | if [ "$#" -ne 2 ]; then 17 | echo "Usage: $0 [instance name] [instance zone]" >&2 18 | exit 1 19 | fi 20 | 21 | INSTANCE=${1} 22 | ZONE=${2} 23 | 24 | echo "Bootstrapping ${INSTANCE} VM in zone ${ZONE}.." >&2 25 | 26 | gcloud compute copy-files \ 27 | scripts/gcloud_bashrc.sh \ 28 | ${INSTANCE}:.bashrc \ 29 | --zone ${ZONE} 30 | gcloud compute copy-files \ 31 | scripts/gcloud_bootstrap.sh \ 32 | ${INSTANCE}: \ 33 | --zone ${ZONE} 34 | 35 | # Include a small .emacs to display tabs sanely. 36 | gcloud compute ssh ${INSTANCE} \ 37 | --zone ${ZONE} \ 38 | --command "echo '(setq tab-width 2)' > .emacs" 39 | gcloud compute ssh ${INSTANCE} \ 40 | --zone ${ZONE} \ 41 | --command "~/gcloud_bootstrap.sh" 42 | -------------------------------------------------------------------------------- /scripts/import_keys.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Imports GPG keys from ../keys into local keyring. 4 | 5 | for k in keys/*.asc; do 6 | gpg --import $k 7 | done 8 | echo "All done." 9 | -------------------------------------------------------------------------------- /scripts/init.sh: -------------------------------------------------------------------------------- 1 | # Shared bash setup for scripts. 2 | 3 | # Fail if any command fails (returns != 0). 4 | set -e 5 | set -o pipefail 6 | 7 | # cfg returns a value loaded from config.yaml. 8 | function cfg() { 9 | if [ "$#" -ne 1 ]; then 10 | echo "Usage: $0 [value]" >&2 11 | return 1 12 | fi 13 | 14 | # if ! /usr/bin/env shyaml -h 2> /dev/null; then 15 | # echo "No shyaml installed. Try 'sudo pip install shyaml'." >&2 16 | # return 3 17 | # fi 18 | VAL=$(cat config.yaml | /usr/bin/env shyaml get-value $1) 19 | if [ -z "$VAL" ]; then 20 | echo "No value $1 in config.yaml. Buggy script? Or config.yaml has changed in the repo and you need to decrypt_config.sh again?" >&2 21 | return 4 22 | fi 23 | echo ${VAL} 24 | return 0 25 | } 26 | 27 | function check_config() { 28 | if [ ! -e "config.yaml" ]; then 29 | echo "No config.yaml present in root of repo. Did you decrypt it with decrypt_config.sh (if you have keys locally) or decrypt_config_remote.sh (if not)?" >&2 30 | exit 1 31 | fi 32 | } 33 | 34 | function check_git_hooks() { 35 | if [ ! -e ".git/hooks/pre-commit" ]; then 36 | echo "Missing git precommit hooks file (.git/hooks/pre-commit). Please run 'symlink_git_hooks.sh'." >&2 37 | exit 2 38 | elif [ ! -e ".git/hooks/pre-push" ]; then 39 | echo "Missing git prepush hooks file (.git/hooks/pre-push). Please run 'symlink_git_hooks.sh'." >&2 40 | exit 3 41 | fi 42 | } 43 | 44 | check_config 45 | check_git_hooks 46 | -------------------------------------------------------------------------------- /scripts/local_mysql.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Starts local mysql server. 4 | sudo /usr/bin/mysqld_safe --datadir='/var/lib/mysql' 5 | -------------------------------------------------------------------------------- /scripts/needs_gofmt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Checks if any files about to be committed need gofmt'ing. 4 | 5 | echo "Checking if any files need gofmt.." >&2 6 | IFS=" 7 | " 8 | if git rev-parse HEAD >/dev/null 2>&1; then 9 | FILES=$(git diff --cached --name-only | grep -e '\.go$'); 10 | else 11 | FILES=$(git ls-files -c | grep -e '\.go$'); 12 | fi 13 | for file in $FILES; do 14 | badfile="$(git --no-pager show :"$file" | gofmt -s -l)" 15 | if test -n "$badfile" ; then 16 | echo "git pre-commit check failed: file needs 'gofmt -s': $file" >&2 17 | exit 1 18 | fi 19 | done 20 | -------------------------------------------------------------------------------- /scripts/patch_appengine.sh: -------------------------------------------------------------------------------- 1 | patch -p1 -d $(dirname $(which goapp)) < scripts/file_watcher.patch 2 | -------------------------------------------------------------------------------- /scripts/pre-commit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Precommit scripts for xelaie. 4 | 5 | if [ -z "${TRUST_ME_I_KNOW_WHAT_I_AM_DOING}" ]; then 6 | scripts/needs_gofmt.sh 7 | else # Allow for a failsafe. 8 | echo "Okay, if you say so. Skipping pre-commit checks. Have fun." >&2 9 | fi 10 | -------------------------------------------------------------------------------- /scripts/pre-push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Prepush hooks for xelaie. 4 | 5 | if [ -z "${TRUST_ME_I_KNOW_WHAT_I_AM_DOING}" ]; then 6 | scripts/run_tests.sh 7 | else # Allow for a failsafe. 8 | echo "Okay, if you say so. Skipping pre-push checks. Have fun." >&2 9 | fi 10 | -------------------------------------------------------------------------------- /scripts/run_gomon.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Runs the "gomon" Docker image. 4 | # 5 | source init.sh || exit 6 | 7 | sudo docker run -t -p 8083:8083 -p 8086:8086 hkjn/gomon:v1 /etc/init.d/influxdb start -------------------------------------------------------------------------------- /scripts/run_monitoring.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Runs monitoring jobs on localhost. 4 | source init.sh || exit 5 | 6 | go build zanaduu3/src/monitoring/dash/xelaiemon 7 | ./xelaiemon -alsologtostderr 8 | -------------------------------------------------------------------------------- /scripts/run_prober.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Runs the prober agains rewards.xelaie.com locally. 4 | go build src/go/prober/prober.go 5 | ./prober -alsologtostderr 6 | -------------------------------------------------------------------------------- /scripts/run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Runs all tests. 4 | # echo "Running all Go tests.." >&2 5 | # goapp test ./... 6 | echo "run_tests.sh is temporarily disabled" >&2 7 | -------------------------------------------------------------------------------- /scripts/style_js.sh: -------------------------------------------------------------------------------- 1 | # Go up until we are in /zanaduu3 directory 2 | function cdroot() 3 | { 4 | while [[ $PWD != '/' && ${PWD##*/} != 'zanaduu3' ]]; do cd ..; done 5 | } 6 | cdroot 7 | 8 | FILE_PATH=src/site/static/js 9 | jscs --fix --config ${FILE_PATH}/.jscsrc ${FILE_PATH} 10 | -------------------------------------------------------------------------------- /scripts/symlink_git_hooks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Symlinks 4 | 5 | cd .git/hooks/ 6 | ln -s ../../scripts/pre-commit.sh pre-commit 7 | ln -s ../../scripts/pre-push.sh pre-push 8 | -------------------------------------------------------------------------------- /scripts/update_db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Updates the tables with the schema changes. 4 | 5 | source init.sh || exit 6 | 7 | HOST=localhost 8 | 9 | DB_NAME=$(cfg mysql.database) 10 | DB_USER=$(cfg mysql.user) 11 | ROOT_PW=$(cfg mysql.root.password) 12 | USER_PW=$(cfg mysql.password) 13 | 14 | cat schemas/helpers/changes.sql | mysql -f --host ${HOST} -u ${DB_USER} -p${USER_PW} ${DB_NAME} 15 | 16 | echo "All done." 17 | -------------------------------------------------------------------------------- /scripts/update_vm_manifest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Updates the monitoring VM from container manifest. 4 | # 5 | CONTAINER_MANIFEST="containers/monitoring.yaml" 6 | ZONE="europe-west1-a" 7 | if [ ! -e ${CONTAINER_MANIFEST} ]; then 8 | echo "Missing manifest file ${CONTAINER_MANIFEST}." >&2 9 | exit 1 10 | fi 11 | 12 | gcloud compute instances add-metadata monitoring \ 13 | --metadata-from-file "google-container-manifest=${CONTAINER_MANIFEST}" \ 14 | --zone ${ZONE} 15 | echo "All done." >&2 16 | -------------------------------------------------------------------------------- /scripts/v2_stage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Stages the App Engine website locally. 4 | 5 | source init.sh || exit 6 | 7 | check_deps.go || exit 8 | 9 | # Copy over the config into the AE app's directory, since we need it 10 | # there for deployment. 11 | cp -v config.yaml src/v2/ 12 | 13 | # Start dev server, allowing access from *any* IP address. (Don't run 14 | # this if such access is undesirable, e.g. if your machine's IP is 15 | # publicly accessible and pages that you're working on that are super 16 | # secret aren't properly guarded by other auth mechanisms). 17 | dev_appserver.py \ 18 | src/v2/app.yaml \ 19 | --admin_port 8011 --port 8012 --host 0.0.0.0 --enable_sendmail=yes & 20 | appserver_PID=$! 21 | 22 | # Start webpack-dev-server to serve webpack bundles. The dev server 23 | # will watch for updates to files that the bundles depends on and 24 | # hot-reload them in the browser. 25 | # 26 | # Keep the port in sync with pageHandler.go. 27 | npm run webpack-dev-server -- \ 28 | --inline \ 29 | --progress \ 30 | --color \ 31 | --port 8014 \ 32 | --output-public-path "http://localhost:8014/static/js/" \ 33 | --hot \ 34 | --config dev.config.js \ 35 | & 36 | webpack_server_PID=$! 37 | 38 | # Kill both dev servers on ctrl-c. 39 | trap ctrl_c INT 40 | function ctrl_c() { 41 | kill $appserver_PID 42 | kill $webpack_server_PID 43 | } 44 | 45 | # https://stackoverflow.com/questions/2935183/bash-infinite-sleep-infinite-blocking 46 | cat 47 | -------------------------------------------------------------------------------- /src/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | } -------------------------------------------------------------------------------- /src/config/config_test.go: -------------------------------------------------------------------------------- 1 | // Tests for config handling 2 | package config 3 | 4 | import ( 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | func TestLoad(t *testing.T) { 10 | c, err := load("../../config.yaml") 11 | if err != nil { 12 | t.Fatalf("Load() failed: %v\n", err) 13 | } 14 | if (reflect.DeepEqual(c, Config{})) { 15 | t.Fatalf("Load() returned empty Config") 16 | } 17 | if (c.MySQL == Config{}.MySQL) { 18 | t.Fatalf("Load() returned empty Config.MySQL") 19 | } 20 | if (c.Site == Config{}.Site) { 21 | t.Fatalf("Load() returned empty Config.Site") 22 | } 23 | if (c.VM == Config{}.VM) { 24 | t.Fatalf("Load() returned empty Config.Vm") 25 | } 26 | if (reflect.DeepEqual(c.Monitoring, Config{}.Monitoring)) { 27 | t.Fatalf("Load() returned empty Config.Monitoring") 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/config/init.go: -------------------------------------------------------------------------------- 1 | // Package config provides a wrapper around config.yaml 2 | package config 3 | 4 | import "log" 5 | 6 | var ( 7 | // We unfortunately must carry around a copy of the config.yaml 8 | // (canonically in the top directory of the repo), as AppEngine 9 | // otherwise won't be smart enough to deploy it to live. (It will 10 | // work on dev, but break the live site.) 11 | XC = Load() 12 | ) 13 | 14 | func init() { 15 | if XC.Site.Session.Auth == "" { 16 | log.Fatalf("FATAL: missing site.session.auth value in config.yaml - can't use encrypted cookies!\n") 17 | } 18 | if XC.Site.Session.Crypt == "" { 19 | log.Fatalf("FATAL: missing site.session.crypt value in config.yaml - can't use encrypted cookies!\n") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/queue_daemon/module.yaml: -------------------------------------------------------------------------------- 1 | application: zanaduu3 2 | module: daemon 3 | version: 002d 4 | runtime: go 5 | api_version: go1 6 | manual_scaling: 7 | instances: 1 8 | instance_class: B1 9 | 10 | handlers: 11 | - url: /.* 12 | script: _go_app 13 | -------------------------------------------------------------------------------- /src/sessions/creds.go: -------------------------------------------------------------------------------- 1 | // creds.go: handles credentials 2 | package sessions 3 | 4 | import ( 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/garyburd/go-oauth/oauth" 9 | ) 10 | 11 | var ( 12 | credsKey = "credentials" // key for session storage 13 | emptyCreds = Credentials{} 14 | FakeCreds = Credentials{&oauth.Credentials{"FAKE_TOKEN", "FAKE_SECRET"}} 15 | ) 16 | 17 | type Credentials struct { 18 | *oauth.Credentials 19 | } 20 | 21 | // Save stores the credentials in session. 22 | func (creds *Credentials) Save(w http.ResponseWriter, r *http.Request) error { 23 | s, err := GetSession(r) 24 | if err != nil { 25 | return fmt.Errorf("couldn't get session: %v", err) 26 | } 27 | 28 | s.Values[credsKey] = *creds 29 | err = s.Save(r, w) 30 | if err != nil { 31 | return fmt.Errorf("failed to save credentials key to session: %v", err) 32 | } 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /src/sessions/error.go: -------------------------------------------------------------------------------- 1 | // error.go defined our own error type 2 | package sessions 3 | 4 | import ( 5 | "fmt" 6 | ) 7 | 8 | type Error *internalError 9 | 10 | // internalError encompasses various kinds of error states we can have 11 | type internalError struct { 12 | // Technical error that happend (e.g. query failed) 13 | Err error 14 | // Message to send to the user 15 | Message string 16 | } 17 | 18 | func NewError(message string, err error) Error { 19 | return &internalError{Message: message, Err: err} 20 | } 21 | 22 | func PassThrough(err error) Error { 23 | if err == nil { 24 | return nil 25 | } 26 | return &internalError{Err: err} 27 | } 28 | 29 | func ToError(e Error) error { 30 | return fmt.Errorf("%s: %v", e.Message, e.Err) 31 | } 32 | -------------------------------------------------------------------------------- /src/site/app.yaml: -------------------------------------------------------------------------------- 1 | application: zanaduu3 2 | version: 002d 3 | runtime: go 4 | api_version: go1 5 | automatic_scaling: 6 | min_idle_instances: 3 7 | max_pending_latency: 0.5s 8 | instance_class: F2 9 | 10 | skip_files: 11 | # AppEngine defaults 12 | - ^(.*/)?#.*#$ 13 | - ^(.*/)?.*~$ 14 | - ^(.*/)?.*\.py[co]$ 15 | - ^(.*/)?.*/RCS/.*$ 16 | - ^(.*/)?\..*$ 17 | # Our additions 18 | - node_modules 19 | 20 | handlers: 21 | - url: /static 22 | static_dir: static 23 | secure: always 24 | 25 | - url: /favicon.ico 26 | static_files: static/icons/favicon.ico 27 | upload: static/icons/favicon.ico 28 | secure: always 29 | 30 | - url: /apple-touch-icon-precomposed.png 31 | static_files: static/images/arbital-icon-120.png 32 | upload: static/images/arbital-icon-120.png 33 | secure: always 34 | 35 | - url: /apple-touch-icon.png 36 | static_files: static/images/arbital-icon-120.png 37 | upload: static/images/arbital-icon-120.png 38 | secure: always 39 | 40 | - url: /.* 41 | script: _go_app 42 | secure: always 43 | 44 | - url: /daemon 45 | script: _go_app 46 | login: admin 47 | -------------------------------------------------------------------------------- /src/site/defaultJsonHandler.go: -------------------------------------------------------------------------------- 1 | // defaultJsonHandler.go returns basic data every page needs. Used for pages 2 | // that don't need any custom data, and therefore don't have custom handlers. 3 | 4 | package site 5 | 6 | import ( 7 | "zanaduu3/src/core" 8 | "zanaduu3/src/pages" 9 | ) 10 | 11 | var defaultHandler = siteHandler{ 12 | URI: "/json/default/", 13 | HandlerFunc: defaultJSONHandlerFunc, 14 | Options: pages.PageOptions{ 15 | AllowAnyone: true, 16 | }, 17 | } 18 | 19 | func defaultJSONHandlerFunc(params *pages.HandlerParams) *pages.Result { 20 | db := params.DB 21 | 22 | returnData := core.NewHandlerData(params.U).SetResetEverything() 23 | err := core.ExecuteLoadPipeline(db, returnData) 24 | if err != nil { 25 | return pages.Fail("Pipeline error", err) 26 | } 27 | 28 | return pages.Success(returnData) 29 | } 30 | -------------------------------------------------------------------------------- /src/site/dismissUpdateHandler.go: -------------------------------------------------------------------------------- 1 | // Handles requests to dismiss updates 2 | 3 | package site 4 | 5 | import ( 6 | "encoding/json" 7 | "net/http" 8 | 9 | "zanaduu3/src/pages" 10 | ) 11 | 12 | type dismissUpdateData struct { 13 | UpdateID string `json:"id"` 14 | } 15 | 16 | var dismissUpdateHandler = siteHandler{ 17 | URI: "/dismissUpdate/", 18 | HandlerFunc: dismissUpdateHandlerFunc, 19 | Options: pages.PageOptions{ 20 | RequireLogin: true, 21 | }, 22 | } 23 | 24 | func dismissUpdateHandlerFunc(params *pages.HandlerParams) *pages.Result { 25 | db := params.DB 26 | u := params.U 27 | 28 | // Decode data 29 | var data dismissUpdateData 30 | err := json.NewDecoder(params.R.Body).Decode(&data) 31 | if err != nil { 32 | return pages.Fail("Couldn't decode request", err).Status(http.StatusBadRequest) 33 | } 34 | 35 | // Dismiss the update 36 | statement := db.NewStatement(` 37 | UPDATE updates 38 | SET dismissed=TRUE 39 | WHERE id=? AND userId=?`) 40 | if _, err := statement.Exec(data.UpdateID, u.ID); err != nil { 41 | return pages.Fail("Couldn't dismiss update", err) 42 | } 43 | 44 | return pages.Success(nil) 45 | } 46 | -------------------------------------------------------------------------------- /src/site/domainPageJsonHandler.go: -------------------------------------------------------------------------------- 1 | // domainPageJsonHandler.go serves data to display domain index page. 2 | 3 | package site 4 | 5 | import ( 6 | "encoding/json" 7 | "net/http" 8 | 9 | "zanaduu3/src/core" 10 | "zanaduu3/src/pages" 11 | ) 12 | 13 | type domainPageData struct { 14 | DomainAlias string 15 | } 16 | 17 | var domainPageHandler = siteHandler{ 18 | URI: "/json/domainPage/", 19 | HandlerFunc: domainPageHandlerFunc, 20 | Options: pages.PageOptions{}, 21 | } 22 | 23 | // domainPageJsonHandler handles the request. 24 | func domainPageHandlerFunc(params *pages.HandlerParams) *pages.Result { 25 | db := params.DB 26 | u := params.U 27 | returnData := core.NewHandlerData(u).SetResetEverything() 28 | 29 | // Decode data 30 | var data domainPageData 31 | decoder := json.NewDecoder(params.R.Body) 32 | err := decoder.Decode(&data) 33 | if err != nil { 34 | return pages.Fail("Couldn't decode request", err).Status(http.StatusBadRequest) 35 | } 36 | 37 | returnData.ResultMap["domain"], err = core.LoadDomainByAlias(db, data.DomainAlias) 38 | if err != nil { 39 | return pages.Fail("Couldn't load domain", err) 40 | } 41 | 42 | return pages.Success(returnData) 43 | } 44 | -------------------------------------------------------------------------------- /src/site/dynamicPage.go: -------------------------------------------------------------------------------- 1 | // dynamicPage.go serves a page which then loads more data dynamically. 2 | 3 | package site 4 | 5 | import ( 6 | "zanaduu3/src/pages" 7 | ) 8 | 9 | var ( 10 | dynamicPage = newPage(dynamicPageRenderer, dynamicTmpls) 11 | ) 12 | 13 | // dynamicPageRenderer renders the dynamic page. 14 | func dynamicPageRenderer(params *pages.HandlerParams) *pages.Result { 15 | return pages.Success(nil) 16 | } 17 | -------------------------------------------------------------------------------- /src/site/feedbackHandler.go: -------------------------------------------------------------------------------- 1 | // feedbackHandler.go adds a new vote for for a page. 2 | 3 | package site 4 | 5 | import ( 6 | "encoding/json" 7 | "net/http" 8 | 9 | "zanaduu3/src/pages" 10 | "zanaduu3/src/tasks" 11 | ) 12 | 13 | // feedbackData contains data given to us in the request. 14 | type feedbackData struct { 15 | Text string 16 | } 17 | 18 | var feedbackHandler = siteHandler{ 19 | URI: "/feedback/", 20 | HandlerFunc: feedbackHandlerFunc, 21 | Options: pages.PageOptions{ 22 | RequireLogin: true, 23 | }, 24 | } 25 | 26 | // feedbackHandlerFunc handles requests to create/update a prior vote. 27 | func feedbackHandlerFunc(params *pages.HandlerParams) *pages.Result { 28 | u := params.U 29 | c := params.C 30 | 31 | decoder := json.NewDecoder(params.R.Body) 32 | var data feedbackData 33 | err := decoder.Decode(&data) 34 | if err != nil { 35 | return pages.Fail("Couldn't decode json", err).Status(http.StatusBadRequest) 36 | } 37 | if data.Text == "" { 38 | return pages.Fail("No text specified", nil).Status(http.StatusBadRequest) 39 | } 40 | 41 | var task tasks.SendFeedbackEmailTask 42 | task.UserID = u.ID 43 | task.UserEmail = u.Email 44 | task.Text = data.Text 45 | if err := tasks.Enqueue(c, &task, nil); err != nil { 46 | c.Errorf("Couldn't enqueue a task: %v", err) 47 | } 48 | 49 | return pages.Success(nil) 50 | } 51 | -------------------------------------------------------------------------------- /src/site/forgotPasswordHandler.go: -------------------------------------------------------------------------------- 1 | // forgotPasswordHandler.go handles requests when the user says they forgot their password 2 | 3 | package site 4 | 5 | import ( 6 | "encoding/json" 7 | "net/http" 8 | 9 | "zanaduu3/src/okta" 10 | "zanaduu3/src/pages" 11 | ) 12 | 13 | // forgotPasswordHandlerData is the data received from the request. 14 | type forgotPasswordHandlerData struct { 15 | Email string 16 | } 17 | 18 | var forgotPasswordHandler = siteHandler{ 19 | URI: "/json/forgotPassword/", 20 | HandlerFunc: forgotPasswordHandlerFunc, 21 | Options: pages.PageOptions{ 22 | AllowAnyone: true, 23 | }, 24 | } 25 | 26 | func forgotPasswordHandlerFunc(params *pages.HandlerParams) *pages.Result { 27 | decoder := json.NewDecoder(params.R.Body) 28 | var data forgotPasswordHandlerData 29 | err := decoder.Decode(&data) 30 | if err != nil { 31 | return pages.Fail("Couldn't decode json", err).Status(http.StatusBadRequest) 32 | } 33 | if len(data.Email) <= 0 { 34 | return pages.Fail("Email is not set", nil).Status(http.StatusBadRequest) 35 | } 36 | 37 | err = okta.ForgotPassword(params.C, data.Email) 38 | if err != nil { 39 | return pages.Fail("Invalid email or password", err) 40 | } 41 | 42 | return pages.Success(nil) 43 | } 44 | -------------------------------------------------------------------------------- /src/site/lensJsonHandler.go: -------------------------------------------------------------------------------- 1 | // lensJsonHandler.go contains the handler for returning JSON with data to display a lens. 2 | 3 | package site 4 | 5 | import ( 6 | "encoding/json" 7 | "net/http" 8 | 9 | "zanaduu3/src/core" 10 | "zanaduu3/src/pages" 11 | ) 12 | 13 | // lensJsonData contains parameters passed in via the request. 14 | type lensJSONData struct { 15 | PageAlias string 16 | } 17 | 18 | var lensHandler = siteHandler{ 19 | URI: "/json/lens/", 20 | HandlerFunc: lensJSONHandler, 21 | } 22 | 23 | // lensJsonHandler handles the request. 24 | func lensJSONHandler(params *pages.HandlerParams) *pages.Result { 25 | u := params.U 26 | db := params.DB 27 | returnData := core.NewHandlerData(u) 28 | 29 | // Decode data 30 | var data lensJSONData 31 | decoder := json.NewDecoder(params.R.Body) 32 | err := decoder.Decode(&data) 33 | if err != nil { 34 | return pages.Fail("Couldn't decode request", err).Status(http.StatusBadRequest) 35 | } 36 | 37 | // Get actual page id 38 | pageID, ok, err := core.LoadAliasToPageID(db, u, data.PageAlias) 39 | if err != nil { 40 | return pages.Fail("Couldn't convert alias", err) 41 | } 42 | if !ok { 43 | return pages.Fail("Couldn't find page", err) 44 | } 45 | 46 | // Load data 47 | core.AddPageToMap(pageID, returnData.PageMap, core.LensFullLoadOptions) 48 | err = core.ExecuteLoadPipeline(db, returnData) 49 | if err != nil { 50 | pages.Fail("Pipeline error", err) 51 | } 52 | 53 | return pages.Success(returnData) 54 | } 55 | -------------------------------------------------------------------------------- /src/site/mailchimpSignupHandler.go: -------------------------------------------------------------------------------- 1 | // mailchimpSignupPage.go serves the mailchimpSignup page. 2 | 3 | package site 4 | 5 | import ( 6 | "encoding/json" 7 | "net/http" 8 | 9 | "zanaduu3/src/mailchimp" 10 | "zanaduu3/src/pages" 11 | ) 12 | 13 | // mailchimpSignupHandlerData is the data received from the request. 14 | type mailchimpSignupHandlerData struct { 15 | Email string 16 | Interests map[string]bool 17 | } 18 | 19 | var mailchimpSignupHandler = siteHandler{ 20 | URI: "/mailchimpSignup/", 21 | HandlerFunc: mailchimpSignupHandlerFunc, 22 | Options: pages.PageOptions{}, 23 | } 24 | 25 | func mailchimpSignupHandlerFunc(params *pages.HandlerParams) *pages.Result { 26 | decoder := json.NewDecoder(params.R.Body) 27 | var data mailchimpSignupHandlerData 28 | err := decoder.Decode(&data) 29 | if err != nil { 30 | return pages.Fail("Couldn't decode json", err).Status(http.StatusBadRequest) 31 | } 32 | if len(data.Email) <= 0 { 33 | return pages.Fail("Email have to be specified", nil).Status(http.StatusBadRequest) 34 | } 35 | 36 | account := &mailchimp.Account{ 37 | Email: data.Email, 38 | Interests: data.Interests, 39 | } 40 | 41 | // Execute request 42 | err = mailchimp.SubscribeUser(params.C, account) 43 | if err != nil { 44 | return pages.Fail("Couldn't subscribe user", err) 45 | } 46 | return pages.Success(nil) 47 | } 48 | -------------------------------------------------------------------------------- /src/site/marksJsonHandler.go: -------------------------------------------------------------------------------- 1 | // marksJsonHandler.go returns marks for a given page. 2 | 3 | package site 4 | 5 | import ( 6 | "encoding/json" 7 | "net/http" 8 | 9 | "zanaduu3/src/core" 10 | "zanaduu3/src/pages" 11 | ) 12 | 13 | // marksJsonData contains parameters passed in via the request. 14 | type marksJSONData struct { 15 | PageID string 16 | } 17 | 18 | var marksHandler = siteHandler{ 19 | URI: "/json/marks/", 20 | HandlerFunc: marksJSONHandler, 21 | Options: pages.PageOptions{ 22 | RequireLogin: true, 23 | }, 24 | } 25 | 26 | // marksJsonHandler handles the request. 27 | func marksJSONHandler(params *pages.HandlerParams) *pages.Result { 28 | db := params.DB 29 | returnData := core.NewHandlerData(params.U) 30 | 31 | // Decode data 32 | var data marksJSONData 33 | err := json.NewDecoder(params.R.Body).Decode(&data) 34 | if err != nil { 35 | return pages.Fail("Couldn't decode request", err).Status(http.StatusBadRequest) 36 | } 37 | if !core.IsIDValid(data.PageID) { 38 | return pages.Fail("Need a valid pageId", err).Status(http.StatusBadRequest) 39 | } 40 | 41 | // Load the marks 42 | loadOptions := &core.PageLoadOptions{ 43 | AllMarks: true, 44 | } 45 | core.AddPageToMap(data.PageID, returnData.PageMap, loadOptions) 46 | err = core.ExecuteLoadPipeline(db, returnData) 47 | if err != nil { 48 | return pages.Fail("Couldn't load pages", err) 49 | } 50 | return pages.Success(returnData) 51 | } 52 | -------------------------------------------------------------------------------- /src/site/newsletterJsonHandler.go: -------------------------------------------------------------------------------- 1 | // newsletterJsonHandler.go serves the newsletter page data. 2 | 3 | package site 4 | 5 | import ( 6 | "zanaduu3/src/core" 7 | "zanaduu3/src/mailchimp" 8 | "zanaduu3/src/pages" 9 | ) 10 | 11 | var newsletterHandler = siteHandler{ 12 | URI: "/json/newsletter/", 13 | HandlerFunc: newsletterJSONHandler, 14 | Options: pages.PageOptions{}, 15 | } 16 | 17 | func newsletterJSONHandler(params *pages.HandlerParams) *pages.Result { 18 | u := params.U 19 | c := params.C 20 | returnData := core.NewHandlerData(u).SetResetEverything() 21 | var err error 22 | 23 | if u.Email != "" { 24 | u.MailchimpInterests, err = mailchimp.GetInterests(c, u.Email) 25 | if err != nil { 26 | return pages.Fail("Couldn't load mailchimp subscriptions", err) 27 | } 28 | } 29 | 30 | return pages.Success(returnData) 31 | } 32 | -------------------------------------------------------------------------------- /src/site/queue.yaml: -------------------------------------------------------------------------------- 1 | # Set the total storage limit for all queues to the free app limit. 2 | # total_storage_limit: 500M 3 | queue: 4 | - name: daemonQueue 5 | mode: pull 6 | # - name: report-monitoring 7 | # mode: push 8 | # bucket_size: 100 9 | # rate: 100/s 10 | -------------------------------------------------------------------------------- /src/site/recentlyCreatedCommentJsonHandler.go: -------------------------------------------------------------------------------- 1 | // Serves JSON for most recently created comments 2 | 3 | package site 4 | 5 | import ( 6 | "zanaduu3/src/core" 7 | "zanaduu3/src/database" 8 | "zanaduu3/src/pages" 9 | ) 10 | 11 | var recentlyCreatedCommentHandler = siteHandler{ 12 | URI: "/json/recentlyCreatedComment/", 13 | HandlerFunc: recentlyCreatedCommentJSONHandler, 14 | Options: pages.PageOptions{ 15 | RequireLogin: true, 16 | }, 17 | } 18 | 19 | const RecentlyCreatedCommentIdsHandlerType = "recentlyCreatedCommentIds" 20 | 21 | func recentlyCreatedCommentJSONHandler(params *pages.HandlerParams) *pages.Result { 22 | return DashboardListJSONHandler(params, LoadRecentlyCreatedComment, RecentlyCreatedCommentIdsHandlerType) 23 | } 24 | 25 | func LoadRecentlyCreatedComment(db *database.DB, returnData *core.CommonHandlerData, privateDomainID string, numToLoad int, 26 | _ *core.PageLoadOptions) ([]string, error) { 27 | // Load recently created by me comment ids 28 | rows := database.NewQuery(` 29 | SELECT p.pageId 30 | FROM pages AS p 31 | JOIN pageInfos AS pi 32 | ON (p.pageId=pi.pageId && p.edit=pi.currentEdit) 33 | WHERE p.creatorId=?`, returnData.User.ID).Add(` 34 | AND pi.seeDomainId=?`, privateDomainID).Add(` 35 | AND pi.type=?`, core.CommentPageType).Add(` 36 | AND`).AddPart(core.PageInfosFilter(returnData.User)).Add(` 37 | ORDER BY pi.createdAt DESC 38 | LIMIT ?`, numToLoad).ToStatement(db).Query() 39 | return core.LoadPageIDs(rows, returnData.PageMap, core.TitlePlusLoadOptions) 40 | } 41 | -------------------------------------------------------------------------------- /src/site/recentlyEditedJsonHandler.go: -------------------------------------------------------------------------------- 1 | // Serves JSON for recently edited pages 2 | 3 | package site 4 | 5 | import ( 6 | "zanaduu3/src/core" 7 | "zanaduu3/src/database" 8 | "zanaduu3/src/pages" 9 | ) 10 | 11 | var recentlyEditedHandler = siteHandler{ 12 | URI: "/json/recentlyEdited/", 13 | HandlerFunc: recentlyEditedJSONHandler, 14 | Options: pages.PageOptions{ 15 | RequireLogin: true, 16 | }, 17 | } 18 | 19 | const RecentlyEditedIdsHandlerType = "recentlyEditedIds" 20 | 21 | func recentlyEditedJSONHandler(params *pages.HandlerParams) *pages.Result { 22 | return DashboardListJSONHandler(params, LoadRecentlyEdited, RecentlyEditedIdsHandlerType) 23 | } 24 | 25 | func LoadRecentlyEdited(db *database.DB, returnData *core.CommonHandlerData, privateDomainID string, numToLoad int, 26 | pageOptions *core.PageLoadOptions) ([]string, error) { 27 | // Load recently created and edited by me page ids 28 | rows := database.NewQuery(` 29 | SELECT p.pageId 30 | FROM pages AS p 31 | JOIN pageInfos AS pi 32 | ON (p.pageId=pi.pageId) 33 | WHERE p.creatorId=?`, returnData.User.ID).Add(` 34 | AND pi.seeDomainId=?`, privateDomainID).Add(` 35 | AND pi.type!=?`, core.CommentPageType).Add(` 36 | AND`).AddPart(core.PageInfosFilter(returnData.User)).Add(` 37 | GROUP BY 1 38 | ORDER BY MAX(p.createdAt) DESC 39 | LIMIT ?`, numToLoad).ToStatement(db).Query() 40 | return core.LoadPageIDs(rows, returnData.PageMap, pageOptions) 41 | } 42 | -------------------------------------------------------------------------------- /src/site/requisitesJsonHandler.go: -------------------------------------------------------------------------------- 1 | // requisitesJsonHandler.go returns all the requisites the user knows 2 | 3 | package site 4 | 5 | import ( 6 | "zanaduu3/src/core" 7 | "zanaduu3/src/pages" 8 | ) 9 | 10 | var requisitesHandler = siteHandler{ 11 | URI: "/json/requisites/", 12 | HandlerFunc: requisitesJSONHandler, 13 | Options: pages.PageOptions{}, 14 | } 15 | 16 | func requisitesJSONHandler(params *pages.HandlerParams) *pages.Result { 17 | u := params.U 18 | db := params.DB 19 | returnData := core.NewHandlerData(u).SetResetEverything() 20 | 21 | // Options to load the pages with 22 | pageOptions := (&core.PageLoadOptions{}).Add(core.TitlePlusLoadOptions) 23 | 24 | // Load all masteries 25 | rows := db.NewStatement(` 26 | SELECT masteryId 27 | FROM userMasteryPairs 28 | WHERE userId=?`).Query(u.GetSomeID()) 29 | _, err := core.LoadPageIDs(rows, returnData.PageMap, pageOptions) 30 | if err != nil { 31 | return pages.Fail("Error while loading masteries", err) 32 | } 33 | 34 | // Load pages. 35 | err = core.ExecuteLoadPipeline(db, returnData) 36 | if err != nil { 37 | return pages.Fail("Pipeline error", err) 38 | } 39 | 40 | return pages.Success(returnData) 41 | } 42 | -------------------------------------------------------------------------------- /src/site/settingsPageJsonHandler.go: -------------------------------------------------------------------------------- 1 | // settingsPageJsonHandler.go contains the handler for returning JSON with data 2 | // to display the settings/invite page. 3 | 4 | package site 5 | 6 | import ( 7 | "zanaduu3/src/core" 8 | "zanaduu3/src/pages" 9 | ) 10 | 11 | type Domain struct { 12 | DomainID string `json:"domainId"` 13 | LongName string `json:"longName"` 14 | } 15 | 16 | var settingsPageHandler = siteHandler{ 17 | URI: "/json/settingsPage/", 18 | HandlerFunc: settingsPageJSONHandler, 19 | Options: pages.PageOptions{ 20 | RequireLogin: true, 21 | }, 22 | } 23 | 24 | // settingsPageJsonHandler renders the settings page. 25 | func settingsPageJSONHandler(params *pages.HandlerParams) *pages.Result { 26 | db := params.DB 27 | u := params.U 28 | returnData := core.NewHandlerData(u).SetResetEverything() 29 | 30 | err := core.ExecuteLoadPipeline(db, returnData) 31 | if err != nil { 32 | return pages.Fail("Pipeline error", err) 33 | } 34 | 35 | return pages.Success(returnData) 36 | } 37 | -------------------------------------------------------------------------------- /src/site/static/html/adminDashboardPage.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 | 6 |
7 | 8 |
9 |
10 | 11 | 12 | 13 | 14 | 17 | 18 |
15 | 16 |
19 |
20 |
21 | -------------------------------------------------------------------------------- /src/site/static/html/bellUpdatesPage.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /src/site/static/html/checkbox.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/site/static/html/commentCount.html: -------------------------------------------------------------------------------- 1 | 2 | comment 3 | 4 | ({{::page.newCommentCount}} new) 5 | 6 | -------------------------------------------------------------------------------- /src/site/static/html/confirmButton.html: -------------------------------------------------------------------------------- 1 |
2 | 8 | 9 | {{tooltipText}} 10 | 11 | 17 | {{tooltipText}} 18 | delete 19 | 20 | 21 |
22 | Are you sure? 23 | yes / 24 | no 25 |
26 |
27 | -------------------------------------------------------------------------------- /src/site/static/html/debatePage.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |

6 | 7 |

8 |
9 |
10 |
11 | 12 |
13 | 14 | New claim 15 | 16 |
17 | 18 |
23 | 24 |
25 |
26 | -------------------------------------------------------------------------------- /src/site/static/html/discussionModePage.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/site/static/html/domainCheckup.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | Pages in this domain 5 |
6 |
7 | 8 | 9 |
10 | 13 |
Parents: 14 | 15 | 16 | 17 |
18 |
First parent's edit domain:
19 | 22 |
23 | 24 |
25 | 26 | 27 |
28 |
29 | -------------------------------------------------------------------------------- /src/site/static/html/domainRoleInput.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | Banned 7 | None 8 | Default 9 | Trusted 10 | Reviewer 11 | Arbiter 12 | Arbitrator 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/site/static/html/editButton.html: -------------------------------------------------------------------------------- 1 |
2 | 8 | create 9 | 10 | 11 | 12 | 13 | 14 | You have an unpublished draft 15 | 16 | 17 |
18 | -------------------------------------------------------------------------------- /src/site/static/html/editDiff.html: -------------------------------------------------------------------------------- 1 | 5 | 6 |
7 | 8 | 9 |
10 | -------------------------------------------------------------------------------- /src/site/static/html/editPageDialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

New page

5 | 6 | 7 | close 8 | 9 |
10 |
11 | 12 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /src/site/static/html/expandIcon.html: -------------------------------------------------------------------------------- 1 | expand_more 2 | -------------------------------------------------------------------------------- /src/site/static/html/explorePage.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | -------------------------------------------------------------------------------- /src/site/static/html/feedbackDialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

Feedback

5 | 6 | 7 | close 8 | 9 |
10 |
11 | 12 |
13 | 17 | 18 | Submit 19 | 20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /src/site/static/html/footer.html: -------------------------------------------------------------------------------- 1 | 2 |

3 | 12 | -------------------------------------------------------------------------------- /src/site/static/html/hedonsModePage.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/site/static/html/inlineComment.html: -------------------------------------------------------------------------------- 1 |
4 | 5 | 6 | expand_less 7 | expand_more 8 | 9 |
10 | -------------------------------------------------------------------------------- /src/site/static/html/learnMore.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |

Learn more

7 |
8 |
9 | 10 | 11 | 12 |
13 | 14 |
15 |
Teaches: {{reasons.teaches}}
16 |
Relies on: {{reasons.reliesOn}}
17 |
Expands on: {{reasons.expandsOn}}
18 |
19 |
20 | 21 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /src/site/static/html/lensToolbarWrapper.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
9 |
-------------------------------------------------------------------------------- /src/site/static/html/likes.html: -------------------------------------------------------------------------------- 1 | 7 | thumb_up 9 | 12 | plus_one 13 | 14 | +{{likeable.likeCount + likeable.myLikeValue}} 15 | 16 | 19 | {{arb.userService.getFullName(userId) + '\n'}} 20 | 21 | 22 | 23 | thumb_up 24 | 25 | {{likeable.likeCount + likeable.myLikeValue}} 26 | 27 | -------------------------------------------------------------------------------- /src/site/static/html/listSubHeader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/site/static/html/maintenanceModePage.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/site/static/html/masteryList.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
9 |
10 |
11 | 12 | 13 | 14 | 15 | , 16 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/site/static/html/multipleChoice.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/site/static/html/newsletterPage.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |

Subscribe to our mailing list

5 |
6 |
7 | Thank you! 8 | 9 | Please check your inbox for the confirmation email. 10 | 11 |
12 |
13 | 14 | 17 | 18 | 19 |
20 |

What are you interested in?

21 | 22 | Receiving general updates about Arbital (once a month) 23 | 24 | 25 | Explaining math topics on Arbital 26 | 27 |
28 |
29 | 34 | 35 |
36 |
37 |
38 |
39 |

40 | 41 |
42 | -------------------------------------------------------------------------------- /src/site/static/html/pageList.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 |
7 | 8 | 9 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | Load more 25 | 26 | 27 | 28 | 29 | Nothing here 30 | 31 |
32 | -------------------------------------------------------------------------------- /src/site/static/html/pageTitle.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | This is a question page 4 | help 5 | 6 | 11 | 13 |
14 |
15 | -------------------------------------------------------------------------------- /src/site/static/html/paragraphEditDialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
14 |
15 |
-------------------------------------------------------------------------------- /src/site/static/html/pathEditor.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 7 |
8 | 9 | 10 |
11 |
12 |
13 |
17 |
18 | reorder 19 | #{{pathPage.pathIndex}}  20 | 21 |
22 | 23 | 24 | 25 | clear 26 | Remove this page from the path 27 | 28 |
29 |
30 |
31 |
32 | 33 | 34 | 36 |
37 | -------------------------------------------------------------------------------- /src/site/static/html/pendingPanel.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | New page submissions 4 | 5 | 6 | 7 |
8 | 11 | 12 |
13 |
14 | None 15 |
16 |
17 | 18 | 19 | Page edit proposals 20 | 21 | 22 | 23 |
24 | 27 | 28 |
29 |
30 | None 31 |
32 |
33 |
34 | -------------------------------------------------------------------------------- /src/site/static/html/primaryPage.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 |
6 | 7 |
8 | -------------------------------------------------------------------------------- /src/site/static/html/readModePage.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/site/static/html/requisiteButton.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | 12 | check_box 13 | Click to mark as wanted 14 | 15 | 16 | bookmark 17 | Click to mark as not known 18 | 19 | 20 | check_box_outline_blank 21 | Click to mark as known 22 | 23 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /src/site/static/html/requisitesPage.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | Your requisites 6 |
7 |
8 | 9 |
13 | 14 | You don't have any requisites yet. 15 | 16 | 20 | Reset all requisites 21 | 22 |
23 |
24 | -------------------------------------------------------------------------------- /src/site/static/html/rows/addedToGroupModeRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | added you to 5 | 8 |
9 |
10 | 11 |
12 |
13 | -------------------------------------------------------------------------------- /src/site/static/html/rows/commentModeRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 |
7 | 8 |
9 |
10 |
11 | -------------------------------------------------------------------------------- /src/site/static/html/rows/draftRow.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/site/static/html/rows/editProposalRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 | proposed an edit to 7 | 8 | 9 |
10 | A new version of the page has been published since then, so this change can only 11 | be applied manually. 12 |
13 |
14 | {{::changeLog.createdAt | relativeDateTime}} 15 |
16 | 17 |
18 | 19 | Approve 21 | 22 | Edit approved! 23 | 24 | 25 |
26 |
27 | -------------------------------------------------------------------------------- /src/site/static/html/rows/inviteReceivedModeRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | Thanks to 4 | 5 | you can now participate in the 6 | 7 | domain. 8 |
9 |
10 | 11 |
12 |
13 | -------------------------------------------------------------------------------- /src/site/static/html/rows/likesModeRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | 6 | 7 | {{::userNames}} {{modeRow.userIds.length == 1 ? 'likes' : 'like'}} 8 | 9 | 10 | 11 | 12 | comment on 13 | 14 | 15 | your edit to 16 | 17 | 18 | 19 | 22 | 23 | 26 | 27 | 28 |   29 | 30 | 31 | 32 |
33 |
34 | 35 | 39 |
40 |
41 | -------------------------------------------------------------------------------- /src/site/static/html/rows/pageToDomainSubmissionRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | wants to add 6 | 7 | to the 8 | 9 | domain. 10 |
11 | 12 |
13 | This submission has been approved by 14 | 15 |
16 |
17 |
18 | {{::submission.createdAt | relativeDateTime}} 19 |
20 |
21 | -------------------------------------------------------------------------------- /src/site/static/html/rows/removedFromGroupModeRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | removed you from 5 | 8 |
9 |
10 | 11 |
12 |
13 | -------------------------------------------------------------------------------- /src/site/static/html/rows/reqsTaughtModeRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | {{::userNames}} 5 | learned from 6 | 7 | 8 |
9 |
10 | 11 |
12 |
13 | -------------------------------------------------------------------------------- /src/site/static/html/rows/taggedForEditRow.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/site/static/html/rows/updates/atMentionUpdateRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | mentioned you in a 5 | 6 | 7 |
8 | 9 | 10 |
-------------------------------------------------------------------------------- /src/site/static/html/rows/updates/changeLogRowLikeButton.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/site/static/html/rows/updates/commentUpdateRow.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /src/site/static/html/rows/updates/deletedPageUpdateRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 6 | 7 | 8 | 9 | deleted 10 | republished 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | — {{::changeLog.newSettingsValue}} 19 | 20 | 21 |
22 |
23 | 24 | 25 | 26 | 27 |
28 | -------------------------------------------------------------------------------- /src/site/static/html/rows/updates/editProposalAcceptedUpdateRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | approved your edit to 5 | 6 | 7 |
8 | 9 |
10 | -------------------------------------------------------------------------------- /src/site/static/html/rows/updates/markUpdateRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | 7 | 8 |
-------------------------------------------------------------------------------- /src/site/static/html/rows/updates/pageEditUpdateRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | proposed an edit to 12 | edited 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | — {{::changeLog.newSettingsValue}} 21 | 22 | 23 | 24 |
25 | 26 | 27 |
28 | 29 |
30 | 31 | Approve 33 | 34 |
35 |
36 | -------------------------------------------------------------------------------- /src/site/static/html/rows/updates/pageToDomainAcceptedUpdateRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | Congrats! 4 | 5 | is now part of the 6 | 7 | domain 8 | 9 |
10 | 11 |
12 | -------------------------------------------------------------------------------- /src/site/static/html/rows/updates/pageToDomainSubmissionUpdateRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | wants to add 6 | to the 7 | domain. 8 | 9 | 10 | This submission has been approved by 11 | 12 | 13 |
14 |
15 | 16 | 17 |
18 | -------------------------------------------------------------------------------- /src/site/static/html/rows/updates/questionMergedUpdateRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | merged 5 | 6 | into 7 | 8 |
9 | 10 | 11 |
12 | -------------------------------------------------------------------------------- /src/site/static/html/rows/updates/resolvedThreadUpdateRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | marked your 5 | 6 | as resolved. 7 | 8 |
9 | 10 |
11 | -------------------------------------------------------------------------------- /src/site/static/html/rows/updates/updateRowDismissButton.html: -------------------------------------------------------------------------------- 1 | 4 | close 5 | Dismiss 6 | 7 | -------------------------------------------------------------------------------- /src/site/static/html/rows/updates/updateRowExpandButton.html: -------------------------------------------------------------------------------- 1 |
2 | 5 | 6 | 7 |
8 | -------------------------------------------------------------------------------- /src/site/static/html/rows/userTrustModeRow.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | promoted you to a 5 | 6 | of the 7 | 8 | domain. 9 |
10 |
11 | 12 |
13 |
14 | -------------------------------------------------------------------------------- /src/site/static/html/slackButton.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/site/static/html/subscribeToDiscussion.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | Watch discussion 7 | 8 | visibility 9 | 10 | 11 | {{page.discussionSubscriberCount + (isSubscribed() ? 1 : 0)}} 12 | 13 | 14 | Receive notifications when new top-level comments are posted 15 | 16 | 17 | Stop receiving comment notifications 18 | 19 | -------------------------------------------------------------------------------- /src/site/static/html/subscribeToMaintain.html: -------------------------------------------------------------------------------- 1 | 5 | build 6 | 7 | {{page.maintainerCount + (isSubscribed() ? 1 : 0)}} 8 | 9 | 10 | Click to subscribe to this page as a maintainer 11 | 12 | 13 | Click to unsubscribe from this page as a maintainer 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/site/static/html/subscribeToUser.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | Follow user 7 | 8 | visibility 9 | 10 | 11 | {{page.userSubscriberCount + (isSubscribed() ? 1 : 0)}} 12 | 13 | 14 | Click to subscribe to this user 15 | 16 | 17 | Click to unsubscribe from this user 18 | 19 | -------------------------------------------------------------------------------- /src/site/static/html/summaryEditDialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | You are editing 5 |
6 | 7 |
17 |
18 |
-------------------------------------------------------------------------------- /src/site/static/html/tableOfContents.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | Contents 5 | 6 | 7 | expand_more 8 | expand_less 9 | 10 |
11 | 12 |
13 |
14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /src/site/static/html/textPopover.html: -------------------------------------------------------------------------------- 1 | 2 |
6 |
7 |
close
8 |
9 | 10 |
11 |
12 |
13 |
14 | -------------------------------------------------------------------------------- /src/site/static/html/userName.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /src/site/static/html/voteSummary.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 19 | block 20 | 21 | -------------------------------------------------------------------------------- /src/site/static/html/writeNewPanel.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | If there is another math topic you'd like to explain or exercises you'd like to write: 12 | go for it! 13 | 14 |
15 | -------------------------------------------------------------------------------- /src/site/static/icons/comment-plus-outline.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/site/static/icons/comment-question-outline.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/site/static/icons/cursor-pointer.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/site/static/icons/facebook-box.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/site/static/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/machine-intelligence/arbital-open-source/ce5ee1c472e39834fbd61b895ba23b501aa96e54/src/site/static/icons/favicon.ico -------------------------------------------------------------------------------- /src/site/static/icons/file-outline.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/site/static/icons/format-header-pound.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/site/static/icons/hand-pointing-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/site/static/icons/link-variant.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/site/static/icons/slack.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/site/static/icons/thumb-down-outline.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/site/static/icons/thumb-up-outline.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/site/static/icons/visibility-outline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 10 | 11 | -------------------------------------------------------------------------------- /src/site/static/images/arbital-icon-120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/machine-intelligence/arbital-open-source/ce5ee1c472e39834fbd61b895ba23b501aa96e54/src/site/static/images/arbital-icon-120.png -------------------------------------------------------------------------------- /src/site/static/images/default-image-link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/machine-intelligence/arbital-open-source/ce5ee1c472e39834fbd61b895ba23b501aa96e54/src/site/static/images/default-image-link.png -------------------------------------------------------------------------------- /src/site/static/images/ic_border_color_black_24dp_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/machine-intelligence/arbital-open-source/ce5ee1c472e39834fbd61b895ba23b501aa96e54/src/site/static/images/ic_border_color_black_24dp_1x.png -------------------------------------------------------------------------------- /src/site/static/images/math.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/machine-intelligence/arbital-open-source/ce5ee1c472e39834fbd61b895ba23b501aa96e54/src/site/static/images/math.png -------------------------------------------------------------------------------- /src/site/static/js/.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "google", 3 | "validateIndentation": "\t", 4 | "maximumLineLength": null, 5 | "requireCurlyBraces": [ 6 | "else", 7 | "for", 8 | "while", 9 | "do", 10 | "try", 11 | "catch", 12 | "case", 13 | "default" 14 | ], 15 | "excludeFiles": ["src/site/static/js/lib/**"] 16 | } 17 | -------------------------------------------------------------------------------- /src/site/static/js/adminDashboardPage.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './angular.ts'; 4 | 5 | // Directive for the Admin Dashboard page. 6 | app.directive('arbAdminDashboardPage', function(arb) { 7 | return { 8 | templateUrl: versionUrl('static/html/adminDashboardPage.html'), 9 | scope: { 10 | data: '=', 11 | }, 12 | controller: function($scope) { 13 | $scope.arb = arb; 14 | }, 15 | }; 16 | }); 17 | -------------------------------------------------------------------------------- /src/site/static/js/arbService.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './angular.ts'; 4 | import {isTouchDevice,isIntIdValid} from './util.ts'; 5 | 6 | // Contains all the services. 7 | app.service('arb', function(analyticsService, autocompleteService, diffService, markService, markdownService, 8 | masteryService, pageService, editService, pathService, popoverService, popupService, stateService, userService, urlService, 9 | signupService) { 10 | var that = this; 11 | 12 | that.analyticsService = analyticsService; 13 | that.autocompleteService = autocompleteService; 14 | that.diffService = diffService; 15 | that.markService = markService; 16 | that.markdownService = markdownService; 17 | that.masteryService = masteryService; 18 | that.pageService = pageService; 19 | that.editService = editService; 20 | that.pathService = pathService; 21 | that.popoverService = popoverService; 22 | that.popupService = popupService; 23 | that.signupService = signupService; 24 | that.stateService = stateService; 25 | that.userService = userService; 26 | that.urlService = urlService; 27 | 28 | this.isTouchDevice = isTouchDevice; 29 | this.isIntIdValid = isIntIdValid; 30 | this.versionUrl = versionUrl; 31 | }); 32 | -------------------------------------------------------------------------------- /src/site/static/js/arbital.d.ts: -------------------------------------------------------------------------------- 1 | // This is declared in dynamicPage.tmpl. It is generated dynamically 2 | // based on the server's version string. 3 | declare function versionUrl(url: string): string; 4 | -------------------------------------------------------------------------------- /src/site/static/js/changeElementType.ts: -------------------------------------------------------------------------------- 1 | // This declaration needs to live in the global namespace, so it 2 | // can't go in util.js (where this is implemented), since util.js 3 | // now exports identifiers and as such is now an ES6 module. 4 | interface JQuery { 5 | changeElementType(newType: string): JQuery; 6 | } 7 | -------------------------------------------------------------------------------- /src/site/static/js/dashboardPage.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './angular.ts'; 4 | 5 | // Directive for the Dashboard page. 6 | app.directive('arbDashboardPage', function(arb) { 7 | return { 8 | templateUrl: versionUrl('static/html/dashboardPage.html'), 9 | scope: { 10 | data: '=' 11 | }, 12 | controller: function($scope) { 13 | $scope.arb = arb; 14 | }, 15 | }; 16 | }); 17 | -------------------------------------------------------------------------------- /src/site/static/js/debatePage.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './angular.ts'; 4 | import {arraysSortFn} from './util.ts'; 5 | 6 | // arb-debate directive displays the project page 7 | app.directive('arbDebate', function($http, $mdDialog, $mdMedia, arb) { 8 | return { 9 | templateUrl: versionUrl('static/html/debatePage.html'), 10 | controller: function($scope) { 11 | $scope.arb = arb; 12 | $scope.pageId = '7qq'; 13 | $scope.page = arb.stateService.pageMap[$scope.pageId]; 14 | console.log($scope.page.childIds); 15 | }, 16 | link: function(scope: any, element, attrs) { 17 | console.log('in link'); 18 | 19 | // Create a dialog for (resuming) editing a new claim 20 | // ROGTODO: figure out whether to use resumeClaimPageId or not? (and how) 21 | var resumeClaimPageId = undefined; 22 | scope.showNewClaimDialog = function(event) { 23 | console.log('in showNewClaimDialog'); 24 | 25 | var title = undefined; 26 | $mdDialog.show({ 27 | templateUrl: versionUrl('static/html/editClaimDialog.html'), 28 | controller: 'EditClaimDialogController', 29 | autoWrap: false, 30 | targetEvent: event, 31 | locals: { 32 | resumePageId: resumeClaimPageId, 33 | title: title, 34 | originalPage: scope.page, 35 | }, 36 | }); 37 | return false; 38 | }; 39 | }, 40 | }; 41 | }); 42 | -------------------------------------------------------------------------------- /src/site/static/js/domainIndexPage.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './angular.ts'; 4 | import {arraysSortFn} from './util.ts'; 5 | 6 | // arb-index directive displays the main page 7 | app.directive('arbDomainIndex', function($http, $mdMedia, arb) { 8 | return { 9 | templateUrl: versionUrl('static/html/domainIndexPage.html'), 10 | scope: { 11 | domain: '=', 12 | }, 13 | controller: function($scope) { 14 | $scope.arb = arb; 15 | 16 | // Tab stuff 17 | $scope.readTab = 0; 18 | $scope.writeTab = 0; 19 | $scope.selectReadTab = function(tab) { 20 | $scope.readTab = tab; 21 | }; 22 | $scope.selectWriteTab = function(tab) { 23 | $scope.writeTab = tab; 24 | }; 25 | }, 26 | }; 27 | }); 28 | -------------------------------------------------------------------------------- /src/site/static/js/editPageDialog.ts: -------------------------------------------------------------------------------- 1 | import app from './angular.ts'; 2 | 3 | // EditPageDialogController is used for editing a page in an mdDialog 4 | app.controller('EditPageDialogController', function($scope, $mdDialog, $timeout, arb, parentIds, resumePageId) { 5 | $scope.arb = arb; 6 | 7 | // Load the page edit 8 | $scope.loadPageEdit = function(pageId) { 9 | arb.pageService.loadEdit({ 10 | pageAlias: pageId, 11 | success: function() { 12 | $scope.pageId = pageId; 13 | }, 14 | }); 15 | }; 16 | 17 | // Create new page 18 | if (!resumePageId) { 19 | arb.pageService.getNewPage({ 20 | type: 'wiki', 21 | parentIds: parentIds, 22 | success: function(newPageId) { 23 | $scope.pageId = newPageId; 24 | }, 25 | }); 26 | } else { 27 | $scope.loadPageEdit(resumePageId); 28 | } 29 | 30 | // Called when the user is done editing the page 31 | $scope.doneFn = function(result) { 32 | $mdDialog.hide(result); 33 | }; 34 | 35 | // Called when the user closed the dialog 36 | $scope.hide = function() { 37 | $mdDialog.hide({hidden: true, pageId: $scope.pageId}); 38 | }; 39 | 40 | $timeout(function() { 41 | // We need this class in the beginning to make sure dialog appears in the 42 | // correct position; but then we need to remove it, otherwise the body 43 | // is not visible. 44 | $('body').removeClass('md-dialog-is-showing'); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /src/site/static/js/explorePage.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './angular.ts'; 4 | 5 | // arb-explore-page directive displays a set of featured domains 6 | app.directive('arbExplorePage', function($http, arb) { 7 | return { 8 | templateUrl: versionUrl('static/html/explorePage.html'), 9 | scope: { 10 | pageId: '@', 11 | }, 12 | controller: function($scope) { 13 | $scope.arb = arb; 14 | }, 15 | }; 16 | }); 17 | -------------------------------------------------------------------------------- /src/site/static/js/feedbackDialog.ts: -------------------------------------------------------------------------------- 1 | import app from './angular.ts'; 2 | 3 | // FeedbackDialogController is used for submitting feedback via mdDialog. 4 | app.controller('FeedbackDialogController', function($scope, $mdDialog, $timeout, $http, arb) { 5 | $scope.arb = arb; 6 | 7 | // Submit feedback 8 | $scope.submitFn = function() { 9 | var data = { 10 | text: $scope.text, 11 | }; 12 | $http({method: 'POST', url: '/feedback/', data: JSON.stringify(data)}); 13 | $mdDialog.hide(); 14 | }; 15 | 16 | // Called when the user closed the dialog 17 | $scope.hide = function() { 18 | $mdDialog.hide(); 19 | }; 20 | 21 | $timeout(function() { 22 | $('.feedback-textarea').focus(); 23 | // We need this class in the beginning to make sure dialog appears in the 24 | // correct position; but then we need to remove it, otherwise the body 25 | // is not visible. 26 | $('body').removeClass('md-dialog-is-showing'); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/site/static/js/hedonsMode.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './angular.ts'; 4 | 5 | // arb-hedons-mode-panel directive displays a list of new hedonic updates 6 | app.directive('arbHedonsModePanel', function($http, arb) { 7 | return { 8 | templateUrl: versionUrl('static/html/listPanel.html'), 9 | scope: { 10 | numToDisplay: '=', 11 | isFullPage: '=', 12 | }, 13 | controller: function($scope) { 14 | $scope.arb = arb; 15 | $scope.allowDense = true; 16 | 17 | $scope.title = 'Achievements'; 18 | $scope.moreLink = '/achievements'; 19 | 20 | arb.stateService.postData('/json/hedons/', { 21 | numPagesToLoad: $scope.numToDisplay, 22 | }, 23 | function(data) { 24 | $scope.modeRows = data.result.modeRows; 25 | $scope.lastView = data.result.lastView; 26 | }); 27 | }, 28 | }; 29 | }); 30 | 31 | // arb-hedons-mode-page is for displaying the entire /achievements page 32 | app.directive('arbHedonsModePage', function($http, arb) { 33 | return { 34 | templateUrl: versionUrl('static/html/hedonsModePage.html'), 35 | scope: { 36 | }, 37 | controller: function($scope) { 38 | $scope.arb = arb; 39 | $scope.allowDense = true; 40 | }, 41 | }; 42 | }); 43 | -------------------------------------------------------------------------------- /src/site/static/js/hiddenText.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './angular.ts'; 4 | 5 | // Directive for hidden text (usually for homework problems) 6 | app.directive('arbHiddenText', function($compile, $timeout, arb) { 7 | return { 8 | scope: { 9 | buttonText: '@', 10 | }, 11 | controller: function($scope) { 12 | $scope.arb = arb; 13 | }, 14 | link: function(scope: any, element, attrs) { 15 | if (!scope.buttonText) return; 16 | 17 | $timeout(function() { 18 | $(element).prepend($compile('' + 22 | '')(scope)); 23 | }); 24 | scope.toggle = function() { 25 | $(element).find('.hidden-text').toggleClass('display-none'); 26 | }; 27 | }, 28 | }; 29 | }); 30 | 31 | -------------------------------------------------------------------------------- /src/site/static/js/lib/angular-recursion.min.js: -------------------------------------------------------------------------------- 1 | angular.module("RecursionHelper",[]).factory("RecursionHelper",["$compile",function(n){return{compile:function(e,o){angular.isFunction(o)&&(o={post:o});var r,p=e.contents().remove();return{pre:o&&o.pre?o.pre:null,post:function(e,t){r||(r=n(p)),r(e,function(n){t.append(n)}),o&&o.post&&o.post.apply(null,arguments)}}}}}]); -------------------------------------------------------------------------------- /src/site/static/js/newsletterPage.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './angular.ts'; 4 | 5 | // arbNewsletter directive displays a way for the user to edit their newsletter preferences 6 | app.directive('arbNewsletter', function($http, arb) { 7 | return { 8 | templateUrl: versionUrl('static/html/newsletterPage.html'), 9 | scope: { 10 | }, 11 | controller: function($scope) { 12 | $scope.arb = arb; 13 | $scope.alreadySubscribed = true; 14 | 15 | var interestMap = arb.userService.user.mailchimpInterests; 16 | if (Object.keys(interestMap).length <= 0) { 17 | interestMap = { 18 | '7ec5d431b0': true, 19 | '7b38bc3921': false, 20 | }; 21 | $scope.alreadySubscribed = false; 22 | } 23 | 24 | $scope.subscribeData = { 25 | email: arb.userService.user.email, 26 | interests: interestMap, 27 | }; 28 | $scope.subscribed = false; 29 | $scope.subscribeToList = function() { 30 | $http({method: 'POST', url: '/mailchimpSignup/', data: JSON.stringify($scope.subscribeData)}) 31 | .success(function(data) { 32 | $scope.subscribed = true; 33 | $scope.subscribeError = undefined; 34 | $scope.$digest(); 35 | }) 36 | .error(function(data) { 37 | $scope.subscribeError = data; 38 | $scope.$digest(); 39 | }); 40 | }; 41 | }, 42 | }; 43 | }); 44 | -------------------------------------------------------------------------------- /src/site/static/js/pageImprovement.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './angular.ts'; 4 | 5 | // arb-page-improvement is the directive which shows what improvements should be made for a page. 6 | app.directive('arbPageImprovement', function($timeout, $http, $compile, arb) { 7 | return { 8 | templateUrl: versionUrl('static/html/pageImprovement.html'), 9 | scope: { 10 | page: '=', 11 | }, 12 | controller: function($scope) { 13 | $scope.arb = arb; 14 | 15 | // Determine which style of bar to show 16 | $scope.qualityTag = arb.pageService.getQualityTag($scope.page.tagIds); 17 | 18 | $scope.shouldShowTags = function() { 19 | return $scope.page.improvementTagIds.length > 0; 20 | }; 21 | $scope.shouldShowTodos = function() { 22 | return $scope.page.todos.length > 0; 23 | }; 24 | $scope.shouldShowRedLinks = function() { 25 | return Object.keys($scope.page.redAliases).length > 0; 26 | }; 27 | $scope.shouldShowImprovements = function() { 28 | return ['a-class', 'featured'].indexOf($scope.qualityTag) < 0; 29 | }; 30 | }, 31 | }; 32 | }); 33 | 34 | -------------------------------------------------------------------------------- /src/site/static/js/paragraphEditDialog.ts: -------------------------------------------------------------------------------- 1 | import app from './angular.ts'; 2 | 3 | // EditPageDialogController is used for editing a page in an mdDialog 4 | app.controller('ParagraphEditDialogController', function($scope, $mdDialog, $timeout, arb, page, paragraphIndex) { 5 | $scope.arb = arb; 6 | $scope.page = page; 7 | $scope.paragraphIndex = paragraphIndex; 8 | 9 | // Load the page edit 10 | arb.pageService.loadEdit({ 11 | pageAlias: page.pageId, 12 | success: function() { 13 | $scope.pageId = page.pageId; 14 | }, 15 | }); 16 | 17 | // Called when the user is done editing the page 18 | $scope.doneFn = function(result) { 19 | arb.pageService.loadEdit({ 20 | pageAlias: page.pageId, 21 | success: function() { 22 | $scope.pageId = page.pageId; 23 | }, 24 | }); 25 | $mdDialog.hide(result); 26 | }; 27 | 28 | // Called when the user closed the dialog 29 | $scope.hide = function() { 30 | $mdDialog.hide({hidden: true, pageId: $scope.pageId}); 31 | }; 32 | 33 | $timeout(function() { 34 | // We need this class in the beginning to make sure dialog appears in the 35 | // correct position; but then we need to remove it, otherwise the body 36 | // is not visible. 37 | $('body').removeClass('md-dialog-is-showing'); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /src/site/static/js/primaryPage.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './angular.ts'; 4 | 5 | // Directive for the entire primary page. 6 | app.directive('arbPrimaryPage', function($compile, $location, $timeout, arb) { 7 | return { 8 | templateUrl: versionUrl('static/html/primaryPage.html'), 9 | scope: { 10 | noFooter: '=', 11 | }, 12 | controller: function($scope) { 13 | $scope.arb = arb; 14 | $scope.page = arb.stateService.primaryPage; 15 | $scope.page.childIds.sort(arb.pageService.getChildSortFunc($scope.page.sortChildrenBy)); 16 | $scope.page.relatedIds.sort(arb.pageService.getChildSortFunc('likes')); 17 | }, 18 | link: function(scope: any, element, attrs) { 19 | if (scope.page.editDomainId == '1') { 20 | element.addClass('math-background'); 21 | } 22 | }, 23 | }; 24 | }); 25 | -------------------------------------------------------------------------------- /src/site/static/js/readMode.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './angular.ts'; 4 | 5 | // arb-read-mode-page hosts the arb-read-mode-panel 6 | app.directive('arbReadModePage', function($http, arb) { 7 | return { 8 | templateUrl: versionUrl('static/html/readModePage.html'), 9 | scope: { 10 | }, 11 | controller: function($scope) { 12 | $scope.arb = arb; 13 | }, 14 | }; 15 | }); 16 | 17 | // arb-read-mode-panel directive displays a list of things to read in a panel 18 | app.directive('arbReadModePanel', function($http, arb) { 19 | return { 20 | templateUrl: versionUrl('static/html/listPanel.html'), 21 | scope: { 22 | numToDisplay: '=', 23 | isFullPage: '=', 24 | type: '@', 25 | domainId: '@', 26 | }, 27 | controller: function($scope) { 28 | $scope.arb = arb; 29 | 30 | arb.stateService.postData('/json/readMode/', { 31 | type: $scope.type, 32 | numPagesToLoad: $scope.numToDisplay, 33 | domainIdConstraint: $scope.domainId, 34 | }, 35 | function(data) { 36 | $scope.modeRows = data.result.modeRows; 37 | $scope.lastView = data.result.lastView; 38 | }); 39 | }, 40 | }; 41 | }); 42 | -------------------------------------------------------------------------------- /src/site/static/js/requisitesPage.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './angular.ts'; 4 | 5 | // Directive for the Requisites page. 6 | app.directive('arbRequisitesPage', function(arb) { 7 | return { 8 | templateUrl: versionUrl('static/html/requisitesPage.html'), 9 | scope: { 10 | }, 11 | controller: function($scope) { 12 | $scope.arb = arb; 13 | 14 | $scope.masteryList = []; 15 | for (var id in arb.masteryService.masteryMap) { 16 | $scope.masteryList.push(id); 17 | } 18 | 19 | // Set all requisites to "not known" 20 | $scope.resetAll = function() { 21 | arb.masteryService.updateMasteryMap({delete: $scope.masteryList}); 22 | }; 23 | }, 24 | }; 25 | }); 26 | -------------------------------------------------------------------------------- /src/site/static/js/rhsButtons.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './angular.ts'; 4 | 5 | // Directive for rhsButtons that appear in $mdBottomSheet 6 | app.controller('RhsButtonsController', function($scope, $mdMedia, $mdBottomSheet, arb) { 7 | $scope.arb = arb; 8 | 9 | $scope.isTinyScreen = !$mdMedia('gt-xs'); 10 | 11 | $scope.newInlineComment = function(isEditorComment) { 12 | $mdBottomSheet.hide({func: 'newInlineComment'}); 13 | }; 14 | $scope.newEditorMark = function(markType) { 15 | $mdBottomSheet.hide({func: 'newEditorMark', params: [markType]}); 16 | }; 17 | $scope.newQueryMark = function() { 18 | $mdBottomSheet.hide({func: 'newQueryMark'}); 19 | }; 20 | $scope.editThisParagraph = function() { 21 | $mdBottomSheet.hide({func: 'editThisParagraph'}); 22 | }; 23 | }); 24 | 25 | -------------------------------------------------------------------------------- /src/site/static/js/settingsPage.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './angular.ts'; 4 | 5 | // Directive for the Settings page. 6 | app.directive('arbSettingsPage', function($http, arb) { 7 | return { 8 | templateUrl: versionUrl('static/html/settingsPage.html'), 9 | scope: { 10 | domains: '=', 11 | invitesSent: '=', 12 | }, 13 | controller: function($scope) { 14 | $scope.arb = arb; 15 | 16 | // Set up frequency types. 17 | $scope.frequencyTypes = { 18 | never: 'Never', 19 | weekly: 'Weekly', 20 | daily: 'Daily', 21 | immediately: 'Immediately', 22 | }; 23 | 24 | // Process settings form submission. 25 | $scope.submitForm = function(event) { 26 | arb.userService.updateSettings(function successFn() { 27 | $scope.submitted = true; 28 | }); 29 | }; 30 | }, 31 | }; 32 | }); 33 | -------------------------------------------------------------------------------- /src/site/static/js/summaryEditDialogController.ts: -------------------------------------------------------------------------------- 1 | import app from './angular.ts'; 2 | 3 | // EditPageDialogController is used for editing a page in an mdDialog 4 | app.controller('SummaryEditDialogController', function($scope, $mdDialog, $timeout, arb, page) { 5 | $scope.arb = arb; 6 | $scope.page = page; 7 | 8 | // Load the page edit 9 | arb.pageService.loadEdit({ 10 | pageAlias: page.pageId, 11 | success: function() { 12 | $scope.pageId = page.pageId; 13 | $scope.loaded = true; 14 | }, 15 | }); 16 | 17 | // Called when the user is done editing the page 18 | $scope.doneFn = function(result) { 19 | arb.pageService.loadEdit({ 20 | pageAlias: page.pageId, 21 | success: function() { 22 | $scope.pageId = page.pageId; 23 | }, 24 | }); 25 | $mdDialog.hide(result); 26 | }; 27 | 28 | // Called when the user closed the dialog 29 | $scope.hide = function() { 30 | $mdDialog.hide({hidden: true, pageId: $scope.pageId}); 31 | }; 32 | 33 | $timeout(function() { 34 | // We need this class in the beginning to make sure dialog appears in the 35 | // correct position; but then we need to remove it, otherwise the body 36 | // is not visible. 37 | $('body').removeClass('md-dialog-is-showing'); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /src/site/static/js/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "sourceMap": true, 4 | "module": "commonjs" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/site/static/js/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": {}, 3 | "globalDependencies": { 4 | "angular": "registry:dt/angular#1.5.0+20160720071806", 5 | "diff-match-patch": "registry:dt/diff-match-patch#1.0.0+20160316155526", 6 | "fbsdk": "registry:dt/fbsdk#0.0.0+20160524084205", 7 | "jquery": "registry:dt/jquery#1.10.0+20160704162008", 8 | "js-cookie": "registry:dt/js-cookie#2.0.0+20160317120654", 9 | "mathjax": "registry:dt/mathjax#0.0.0+20160317120654", 10 | "moment": "registry:dt/moment#2.8.0+20160316155526", 11 | "moment-node": "registry:dt/moment-node#2.11.1+20160511043338" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/site/static/js/untitled: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/machine-intelligence/arbital-open-source/ce5ee1c472e39834fbd61b895ba23b501aa96e54/src/site/static/js/untitled -------------------------------------------------------------------------------- /src/site/static/js/userPage.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './angular.ts'; 4 | 5 | // Directive for the User page. 6 | app.directive('arbUserPage', function(arb) { 7 | return { 8 | templateUrl: versionUrl('static/html/userPage.html'), 9 | scope: { 10 | userId: '@', 11 | userPageData: '=', 12 | }, 13 | controller: function($scope) { 14 | $scope.arb = arb; 15 | 16 | $scope.userDomainMembershipMap = arb.userService.userMap[$scope.userId].domainMembershipMap; 17 | for (let domainId in arb.userService.user.domainMembershipMap) { 18 | if (!(domainId in $scope.userDomainMembershipMap)) { 19 | $scope.userDomainMembershipMap[domainId] = {role: ''}; 20 | } 21 | } 22 | }, 23 | }; 24 | }); 25 | -------------------------------------------------------------------------------- /src/site/static/scss/constants.scss: -------------------------------------------------------------------------------- 1 | // All the z-indices we use 2 | $inlineCommentIconZ: 2; 3 | $composeFabZ: 50; 4 | $popupDivZ: 55; 5 | $popoverZ: 80; 6 | $fixedOverlayZ: 1000; 7 | $changeSpeedZ: 3; 8 | $floaterToolbarZ: 2; 9 | 10 | // Colors that are the same as we set for mdThemingProvider 11 | //http://www.google.com/design/spec/style/color.html#color-color-palette 12 | $primary-color: #009688; // teal (500) 13 | $primary-hue-1: #E0F2F1; // 100 14 | $primary-hue-2: #00796B; // 700 15 | $primary-hue-3: #004D40; // 900 16 | $accent-color: #FF5722; // deep-orange (500) 17 | $accent-hue-1: #FFCCBC; // 100 18 | $accent-hue-2: #E64A19; // 700 19 | $accent-hue-3: #F16700; // custom (opposite to teal500) 20 | $warn-color: #F44336; // red (500) 21 | $warn-hue-1: #FFCDD2; // 100 22 | $warn-hue-2: #D32F2F; // 700 23 | $warn-hue-3: #B71C1C; // 900 24 | 25 | $background-color: #f7f7f7; 26 | 27 | $link-color: #137abd; 28 | $light-link-color: lighten(#137abd, 40%); 29 | $very-light-link-color: #e8f1f7; 30 | 31 | $post-color: #7abd13; 32 | $claim-color: #bd7abd; 33 | -------------------------------------------------------------------------------- /src/site/static/scss/ng-sortable.scss: -------------------------------------------------------------------------------- 1 | // CSS for the sortable list of things library 2 | 3 | .as-sortable-item, .as-sortable-placeholder { 4 | display: block; 5 | } 6 | 7 | .as-sortable-item { 8 | -ms-touch-action: none; 9 | touch-action: none; 10 | } 11 | 12 | .as-sortable-item-handle { 13 | cursor: move; 14 | cursor: -webkit-grab; 15 | cursor: -moz-grab; 16 | } 17 | 18 | .as-sortable-placeholder { 19 | } 20 | 21 | .as-sortable-drag { 22 | position: absolute; 23 | pointer-events: none; 24 | z-index: 9999; 25 | } 26 | 27 | .as-sortable-hidden { 28 | display: none !important; 29 | } 30 | 31 | .as-sortable-un-selectable { 32 | -webkit-touch-callout: none; 33 | -webkit-user-select: none; 34 | -khtml-user-select: none; 35 | -moz-user-select: none; 36 | -ms-user-select: none; 37 | user-select: none; 38 | } 39 | 40 | 41 | // === Optional === 42 | 43 | .as-sortable-item, .as-sortable-placeholder { 44 | min-height: 20px; 45 | margin: 5px 2px 10px 1px; 46 | } 47 | 48 | .as-sortable-item { 49 | background-color: #ffffff; 50 | } 51 | 52 | .as-sortable-item-handle { 53 | } 54 | 55 | .as-sortable-placeholder { 56 | border: 1px dashed darkgrey; 57 | box-sizing: border-box; 58 | background-color: #dbdbdb; 59 | } 60 | 61 | .as-sortable-drag { 62 | opacity: .8; 63 | } 64 | 65 | .as-sortable-hidden { 66 | } 67 | -------------------------------------------------------------------------------- /src/site/tsx: -------------------------------------------------------------------------------- 1 | static/tsx -------------------------------------------------------------------------------- /src/site/userPopoverJsonHandler.go: -------------------------------------------------------------------------------- 1 | // userPopoverJsonHandler.go contains the handler for returning JSON with user data 2 | 3 | package site 4 | 5 | import ( 6 | "encoding/json" 7 | "net/http" 8 | 9 | "zanaduu3/src/core" 10 | "zanaduu3/src/pages" 11 | ) 12 | 13 | // userPopoverJsonData contains parameters passed in via the request. 14 | type userPopoverJSONData struct { 15 | UserID string 16 | } 17 | 18 | var userPopoverHandler = siteHandler{ 19 | URI: "/json/userPopover/", 20 | HandlerFunc: userPopoverJSONHandler, 21 | } 22 | 23 | // userPopoverJsonHandler handles the request. 24 | func userPopoverJSONHandler(params *pages.HandlerParams) *pages.Result { 25 | db := params.DB 26 | returnData := core.NewHandlerData(params.U) 27 | 28 | // Decode data 29 | var data userPopoverJSONData 30 | decoder := json.NewDecoder(params.R.Body) 31 | err := decoder.Decode(&data) 32 | if err != nil { 33 | return pages.Fail("Couldn't decode request", err).Status(http.StatusBadRequest) 34 | } 35 | 36 | // Load data 37 | core.AddUserToMap(data.UserID, returnData.UserMap) 38 | // This page is the user page, this will load user summary 39 | core.AddPageToMap(data.UserID, returnData.PageMap, core.IntrasitePopoverLoadOptions) 40 | err = core.ExecuteLoadPipeline(db, returnData) 41 | if err != nil { 42 | pages.Fail("Pipeline error", err) 43 | } 44 | 45 | return pages.Success(returnData) 46 | } 47 | -------------------------------------------------------------------------------- /src/site/verifyEmailPage.go: -------------------------------------------------------------------------------- 1 | // verifyEmailPage.go user is directed here when they click on a link to verify email 2 | 3 | package site 4 | 5 | import ( 6 | "zanaduu3/src/okta" 7 | "zanaduu3/src/pages" 8 | ) 9 | 10 | var verifyEmailPage = newPage(verifyEmailRenderer, dynamicTmpls) 11 | 12 | func verifyEmailRenderer(params *pages.HandlerParams) *pages.Result { 13 | c := params.C 14 | 15 | sptoken := params.R.FormValue("sptoken") 16 | if sptoken == "" { 17 | return pages.Fail("Are you in the right place? (No sptoken found.)", nil) 18 | } 19 | 20 | err := okta.VerifyEmail(c, params.R.FormValue("sptoken")) 21 | if err != nil { 22 | return pages.Fail("Verification failed", err) 23 | } 24 | 25 | return pages.RedirectWith("/login") 26 | } 27 | -------------------------------------------------------------------------------- /src/site/webpack/base.config.js: -------------------------------------------------------------------------------- 1 | var merge = require('deepmerge'); 2 | var path = require('path'); 3 | 4 | var config = { 5 | entry: './entry.js', 6 | output: { 7 | path: '../static/js', 8 | filename: 'bundle.js', 9 | }, 10 | module: { 11 | noParse: /js\/lib\//, 12 | loaders: [ 13 | // TypeScript 14 | { test: /\.tsx?$/, loader: 'ts-loader' }, 15 | 16 | // SCSS 17 | { test: /\.scss$/, loaders: ['style', 'css', 'sass'] }, 18 | 19 | // Angular Templates 20 | { 21 | test: /\.html$/, 22 | loader: 'ngtemplate?relativeTo=site/!html', 23 | }, 24 | ] 25 | }, 26 | resolve: { 27 | root: [ 28 | path.resolve('../static'), 29 | path.resolve('../../node_modules'), 30 | ], 31 | }, 32 | }; 33 | 34 | exports.merge = function(extra) { 35 | return merge(config, extra); 36 | } 37 | -------------------------------------------------------------------------------- /src/site/webpack/dev.config.js: -------------------------------------------------------------------------------- 1 | var base = require('./base.config.js'); 2 | 3 | module.exports = base.merge({ 4 | devtool: 'source-map', 5 | module: { 6 | preLoaders: [ 7 | // Re-process sourcemaps from TypeScript. 8 | { test: /\.js$/, loader: "source-map-loader" }, 9 | ], 10 | }, 11 | }) 12 | -------------------------------------------------------------------------------- /src/site/webpack/prod.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var base = require('./base.config.js'); 3 | 4 | module.exports = base.merge({ 5 | plugins: [ 6 | new webpack.optimize.UglifyJsPlugin({ 7 | mangle: false, // Mangling currently breaks Angular. 8 | compress: {warnings: false} // The warnings are too verbose. 9 | }), 10 | ] 11 | }) 12 | -------------------------------------------------------------------------------- /src/tasks/init.go: -------------------------------------------------------------------------------- 1 | // init.go contains all the structs for the tasks that go into the queue. 2 | package tasks 3 | 4 | func init() { 5 | } 6 | -------------------------------------------------------------------------------- /src/v2/app.yaml: -------------------------------------------------------------------------------- 1 | application: zanaduu3 2 | version: 002d 3 | runtime: go 4 | api_version: go1 5 | automatic_scaling: 6 | min_idle_instances: 3 7 | max_pending_latency: 0.5s 8 | instance_class: F2 9 | 10 | skip_files: 11 | # AppEngine defaults 12 | - ^(.*/)?#.*#$ 13 | - ^(.*/)?.*~$ 14 | - ^(.*/)?.*\.py[co]$ 15 | - ^(.*/)?.*/RCS/.*$ 16 | - ^(.*/)?\..*$ 17 | # Our additions 18 | - node_modules 19 | 20 | handlers: 21 | - url: /static 22 | static_dir: static 23 | secure: always 24 | 25 | - url: /favicon.ico 26 | static_files: static/icons/favicon.ico 27 | upload: static/icons/favicon.ico 28 | secure: always 29 | 30 | - url: /apple-touch-icon-precomposed.png 31 | static_files: static/images/arbital-icon-120.png 32 | upload: static/images/arbital-icon-120.png 33 | secure: always 34 | 35 | - url: /apple-touch-icon.png 36 | static_files: static/images/arbital-icon-120.png 37 | upload: static/images/arbital-icon-120.png 38 | secure: always 39 | 40 | - url: /.* 41 | script: _go_app 42 | secure: always 43 | 44 | - url: /daemon 45 | script: _go_app 46 | login: admin 47 | -------------------------------------------------------------------------------- /src/v2/dynamicPage.go: -------------------------------------------------------------------------------- 1 | // dynamicPage.go serves a page which then loads more data dynamically. 2 | 3 | package site 4 | 5 | import ( 6 | "zanaduu3/src/pages" 7 | ) 8 | 9 | var ( 10 | dynamicPage = newPage(dynamicPageRenderer, dynamicTmpls) 11 | ) 12 | 13 | // dynamicPageRenderer renders the dynamic page. 14 | func dynamicPageRenderer(params *pages.HandlerParams) *pages.Result { 15 | return pages.Success(nil) 16 | } 17 | -------------------------------------------------------------------------------- /src/v2/init.go: -------------------------------------------------------------------------------- 1 | // Package site is used to manage our website 2 | 3 | package site 4 | 5 | import ( 6 | "fmt" 7 | "net/http" 8 | 9 | "zanaduu3/src/core" 10 | "zanaduu3/src/logger" 11 | "zanaduu3/src/sessions" 12 | 13 | "github.com/gorilla/mux" 14 | ) 15 | 16 | var ( 17 | dynamicTmpls = []string{"tmpl/dynamicPage.tmpl"} 18 | ) 19 | 20 | func ahHandler(w http.ResponseWriter, r *http.Request) { 21 | w.WriteHeader(http.StatusOK) 22 | } 23 | 24 | func init() { 25 | logger.SetLogger(func(r *http.Request) logger.Logger { 26 | return sessions.NewContext(r) 27 | }) 28 | 29 | r := mux.NewRouter() 30 | s := r.Host(fmt.Sprintf("{www:w?w?w?\\.?}{subdomain:%s}{subdomaindot:\\.?}%s", core.SubdomainAliasOrPageIDRegexpStr, sessions.GetMuxDomain())).Subrouter() 31 | s.StrictSlash(true) 32 | 33 | // Pages 34 | s.HandleFunc("/", pageHandlerWrapper(&dynamicPage)).Methods("GET", "HEAD") 35 | 36 | // JSON handlers (API) 37 | s.HandleFunc("/_ah/start", ahHandler).Methods("GET") 38 | 39 | http.Handle("/", r) 40 | } 41 | -------------------------------------------------------------------------------- /src/v2/webpack/base.config.js: -------------------------------------------------------------------------------- 1 | var merge = require('deepmerge'); 2 | var path = require('path'); 3 | 4 | var config = { 5 | entry: './entry.js', 6 | output: { 7 | path: '../static/js', 8 | filename: 'bundle.js', 9 | }, 10 | module: { 11 | noParse: /js\/lib\//, 12 | loaders: [ 13 | // TypeScript 14 | { test: /\.tsx?$/, loader: 'ts-loader' }, 15 | 16 | // SCSS 17 | { test: /\.scss$/, loaders: ['style', 'css', 'sass'] }, 18 | 19 | // Angular Templates 20 | { 21 | test: /\.html$/, 22 | loader: 'ngtemplate?relativeTo=site/!html', 23 | }, 24 | ] 25 | }, 26 | resolve: { 27 | root: [ 28 | path.resolve('../static'), 29 | path.resolve('../../node_modules'), 30 | ], 31 | }, 32 | }; 33 | 34 | exports.merge = function(extra) { 35 | return merge(config, extra); 36 | } 37 | -------------------------------------------------------------------------------- /src/v2/webpack/dev.config.js: -------------------------------------------------------------------------------- 1 | var base = require('./base.config.js'); 2 | 3 | module.exports = base.merge({ 4 | devtool: 'source-map', 5 | module: { 6 | preLoaders: [ 7 | // Re-process sourcemaps from TypeScript. 8 | { test: /\.js$/, loader: "source-map-loader" }, 9 | ], 10 | }, 11 | }) 12 | -------------------------------------------------------------------------------- /src/v2/webpack/entry.js: -------------------------------------------------------------------------------- 1 | // Our style sheets 2 | require('scss/arbital.scss'); 3 | 4 | // All AngularJS templates. 5 | var templates = require.context( 6 | 'html', 7 | true, 8 | /\.html$/ 9 | ) 10 | templates.keys().forEach(function(key) { 11 | templates(key); 12 | }); 13 | 14 | //require('js/angular.ts'); 15 | -------------------------------------------------------------------------------- /src/v2/webpack/prod.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var base = require('./base.config.js'); 3 | 4 | module.exports = base.merge({ 5 | plugins: [ 6 | new webpack.optimize.UglifyJsPlugin({ 7 | mangle: false, // Mangling currently breaks Angular. 8 | compress: {warnings: false} // The warnings are too verbose. 9 | }), 10 | ] 11 | }) 12 | -------------------------------------------------------------------------------- /test/e2e/README.md: -------------------------------------------------------------------------------- 1 | #End 2 End Testing (Protractor) 2 | To run the end-2-end tests against the application you use [Protractor](https://github.com/angular/protractor). 3 | 4 | ## Starting the Web Server 5 | In either case you will need the application to be running via the web-server. 6 | From the root folder of the repository run: 7 | 8 | ``` 9 | npm start 10 | ``` 11 | 12 | The application should now be available at `http://localhost:8000/app/index.html` 13 | 14 | ## Testing with Protractor 15 | 16 | As a one-time setup, download webdriver. 17 | ``` 18 | npm run update-webdriver 19 | ``` 20 | 21 | Start the Protractor test runner using the e2e configuration: 22 | 23 | ``` 24 | npm run protractor 25 | ``` 26 | -------------------------------------------------------------------------------- /test/e2e/scenarios.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* http://docs.angularjs.org/guide/dev_guide.e2e-testing */ 4 | 5 | describe('arbital', function() { 6 | 7 | describe('Main Page', function() { 8 | 9 | it('main page should have a search box', function() { 10 | browser.get(''); 11 | var searchbox = element(by.id('input-0')); 12 | console.log("test"); 13 | console.log(searchbox); 14 | searchbox.sendKeys('Arbital'); 15 | //console.log(browser.getTitle()); 16 | //console.log(browser); 17 | //expect(browser.getTitle()).toEqual('Arbital'); 18 | }); 19 | 20 | it('settings page should have settings', function() { 21 | browser.get('settings'); 22 | var frequency = element(by.model('userService.user.emailFrequency')); 23 | console.log("test"); 24 | console.log(frequency); 25 | //console.log(browser.getTitle()); 26 | //console.log(browser); 27 | //expect(browser.getTitle()).toEqual('Arbital'); 28 | }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /test/protractor-conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | allScriptsTimeout: 11000, 3 | 4 | specs: [ 5 | 'e2e/*.js' 6 | ], 7 | 8 | capabilities: { 9 | 'browserName': 'chrome' 10 | }, 11 | 12 | chromeOnly: true, 13 | 14 | baseUrl: 'http://localhost:8012/', 15 | 16 | framework: 'jasmine', 17 | 18 | jasmineNodeOpts: { 19 | defaultTimeoutInterval: 30000 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /test/unit/controllersSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jasmine specs for controllers go here */ 4 | describe('zan controllers', function() { 5 | 6 | describe('ArbitalCtrl', function(){ 7 | 8 | beforeEach(module('arbital')); 9 | 10 | var $controller; 11 | var scope, ctrl, $httpBackend; 12 | 13 | beforeEach(inject(function(_$controller_){ 14 | $controller = _$controller_; 15 | })); 16 | 17 | // The injector ignores leading and trailing underscores here (i.e. _$httpBackend_). 18 | // This allows us to inject a service but then attach it to a variable 19 | // with the same name as the service in order to avoid a name conflict. 20 | beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) { 21 | $httpBackend = _$httpBackend_; 22 | 23 | scope = $rootScope.$new(); 24 | ctrl = $controller('ArbitalCtrl', {$scope: scope}); 25 | })); 26 | /* 27 | it('should create "karmaTestValue" model with value 3', inject(function($controller) { 28 | var scope = {}, 29 | ctrl = $controller('ArbitalCtrl', {$scope:scope}); 30 | 31 | expect(scope.karmaTestValue).toBe(3); 32 | })); 33 | */ 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/unit/filtersSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jasmine specs for filters go here */ 4 | 5 | describe('filter', function() { 6 | 7 | }); 8 | -------------------------------------------------------------------------------- /test/unit/servicesSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jasmine specs for services go here */ 4 | 5 | describe('service', function() { 6 | 7 | }); 8 | -------------------------------------------------------------------------------- /vendor/github.com/dustin/go-humanize/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2005-2008 Dustin Sallings 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | 21 | 22 | -------------------------------------------------------------------------------- /vendor/github.com/dustin/go-humanize/big.go: -------------------------------------------------------------------------------- 1 | package humanize 2 | 3 | import ( 4 | "math/big" 5 | ) 6 | 7 | // order of magnitude (to a max order) 8 | func oomm(n, b *big.Int, maxmag int) (float64, int) { 9 | mag := 0 10 | m := &big.Int{} 11 | for n.Cmp(b) >= 0 { 12 | n.DivMod(n, b, m) 13 | mag++ 14 | if mag == maxmag && maxmag >= 0 { 15 | break 16 | } 17 | } 18 | return float64(n.Int64()) + (float64(m.Int64()) / float64(b.Int64())), mag 19 | } 20 | 21 | // total order of magnitude 22 | // (same as above, but with no upper limit) 23 | func oom(n, b *big.Int) (float64, int) { 24 | mag := 0 25 | m := &big.Int{} 26 | for n.Cmp(b) >= 0 { 27 | n.DivMod(n, b, m) 28 | mag++ 29 | } 30 | return float64(n.Int64()) + (float64(m.Int64()) / float64(b.Int64())), mag 31 | } 32 | -------------------------------------------------------------------------------- /vendor/github.com/dustin/go-humanize/commaf.go: -------------------------------------------------------------------------------- 1 | // +build go1.6 2 | 3 | package humanize 4 | 5 | import ( 6 | "bytes" 7 | "math/big" 8 | "strings" 9 | ) 10 | 11 | // BigCommaf produces a string form of the given big.Float in base 10 12 | // with commas after every three orders of magnitude. 13 | func BigCommaf(v *big.Float) string { 14 | buf := &bytes.Buffer{} 15 | if v.Sign() < 0 { 16 | buf.Write([]byte{'-'}) 17 | v.Abs(v) 18 | } 19 | 20 | comma := []byte{','} 21 | 22 | parts := strings.Split(v.Text('f', -1), ".") 23 | pos := 0 24 | if len(parts[0])%3 != 0 { 25 | pos += len(parts[0]) % 3 26 | buf.WriteString(parts[0][:pos]) 27 | buf.Write(comma) 28 | } 29 | for ; pos < len(parts[0]); pos += 3 { 30 | buf.WriteString(parts[0][pos : pos+3]) 31 | buf.Write(comma) 32 | } 33 | buf.Truncate(buf.Len() - 1) 34 | 35 | if len(parts) > 1 { 36 | buf.Write([]byte{'.'}) 37 | buf.WriteString(parts[1]) 38 | } 39 | return buf.String() 40 | } 41 | -------------------------------------------------------------------------------- /vendor/github.com/dustin/go-humanize/ftoa.go: -------------------------------------------------------------------------------- 1 | package humanize 2 | 3 | import "strconv" 4 | 5 | func stripTrailingZeros(s string) string { 6 | offset := len(s) - 1 7 | for offset > 0 { 8 | if s[offset] == '.' { 9 | offset-- 10 | break 11 | } 12 | if s[offset] != '0' { 13 | break 14 | } 15 | offset-- 16 | } 17 | return s[:offset+1] 18 | } 19 | 20 | // Ftoa converts a float to a string with no trailing zeros. 21 | func Ftoa(num float64) string { 22 | return stripTrailingZeros(strconv.FormatFloat(num, 'f', 6, 64)) 23 | } 24 | -------------------------------------------------------------------------------- /vendor/github.com/dustin/go-humanize/humanize.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package humanize converts boring ugly numbers to human-friendly strings and back. 3 | 4 | Durations can be turned into strings such as "3 days ago", numbers 5 | representing sizes like 82854982 into useful strings like, "83MB" or 6 | "79MiB" (whichever you prefer). 7 | */ 8 | package humanize 9 | -------------------------------------------------------------------------------- /vendor/github.com/dustin/go-humanize/ordinals.go: -------------------------------------------------------------------------------- 1 | package humanize 2 | 3 | import "strconv" 4 | 5 | // Ordinal gives you the input number in a rank/ordinal format. 6 | // 7 | // Ordinal(3) -> 3rd 8 | func Ordinal(x int) string { 9 | suffix := "th" 10 | switch x % 10 { 11 | case 1: 12 | if x%100 != 11 { 13 | suffix = "st" 14 | } 15 | case 2: 16 | if x%100 != 12 { 17 | suffix = "nd" 18 | } 19 | case 3: 20 | if x%100 != 13 { 21 | suffix = "rd" 22 | } 23 | } 24 | return strconv.Itoa(x) + suffix 25 | } 26 | -------------------------------------------------------------------------------- /vendor/github.com/dyatlov/go-opengraph/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Vitaly Dyatlov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /vendor/github.com/dyatlov/go-opengraph/examples/simple.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/dyatlov/go-opengraph/opengraph" 8 | ) 9 | 10 | func main() { 11 | html := ` 12 | 13 | ` 14 | 15 | og := opengraph.NewOpenGraph() 16 | err := og.ProcessHTML(strings.NewReader(html)) 17 | 18 | if err != nil { 19 | fmt.Println(err) 20 | return 21 | } 22 | 23 | fmt.Printf("Type: %s\n", og.Type) 24 | fmt.Printf("Title: %s\n", og.Title) 25 | fmt.Printf("URL: %s\n", og.URL) 26 | fmt.Printf("String/JSON Representation: %s\n", og) 27 | } 28 | -------------------------------------------------------------------------------- /vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | ## Reporting Issues 4 | 5 | Before creating a new Issue, please check first if a similar Issue [already exists](https://github.com/go-sql-driver/mysql/issues?state=open) or was [recently closed](https://github.com/go-sql-driver/mysql/issues?direction=desc&page=1&sort=updated&state=closed). 6 | 7 | ## Contributing Code 8 | 9 | By contributing to this project, you share your code under the Mozilla Public License 2, as specified in the LICENSE file. 10 | Don't forget to add yourself to the AUTHORS file. 11 | 12 | ### Code Review 13 | 14 | Everyone is invited to review and comment on pull requests. 15 | If it looks fine to you, comment with "LGTM" (Looks good to me). 16 | 17 | If changes are required, notice the reviewers with "PTAL" (Please take another look) after committing the fixes. 18 | 19 | Before merging the Pull Request, at least one [team member](https://github.com/go-sql-driver?tab=members) must have commented with "LGTM". 20 | 21 | ## Development Ideas 22 | 23 | If you are looking for ideas for code contributions, please check our [Development Ideas](https://github.com/go-sql-driver/mysql/wiki/Development-Ideas) Wiki page. 24 | -------------------------------------------------------------------------------- /vendor/github.com/go-sql-driver/mysql/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Issue description 2 | Tell us what should happen and what happens instead 3 | 4 | ### Example code 5 | ```go 6 | If possible, please enter some example code here to reproduce the issue. 7 | ``` 8 | 9 | ### Error log 10 | ``` 11 | If you have an error log, please paste it here. 12 | ``` 13 | 14 | ### Configuration 15 | *Driver version (or git SHA):* 16 | 17 | *Go version:* run `go version` in your console 18 | 19 | *Server version:* E.g. MySQL 5.6, MariaDB 10.0.20 20 | 21 | *Server OS:* E.g. Debian 8.1 (Jessie), Windows 10 22 | -------------------------------------------------------------------------------- /vendor/github.com/go-sql-driver/mysql/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | Please explain the changes you made here. 3 | 4 | ### Checklist 5 | - [ ] Code compiles correctly 6 | - [ ] Created tests which fail without the change (if possible) 7 | - [ ] All tests passing 8 | - [ ] Extended the README / documentation, if necessary 9 | - [ ] Added myself / the copyright holder to the AUTHORS file 10 | -------------------------------------------------------------------------------- /vendor/github.com/go-sql-driver/mysql/appengine.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | // +build appengine 10 | 11 | package mysql 12 | 13 | import ( 14 | "appengine/cloudsql" 15 | ) 16 | 17 | func init() { 18 | RegisterDial("cloudsql", cloudsql.Dial) 19 | } 20 | -------------------------------------------------------------------------------- /vendor/github.com/go-sql-driver/mysql/result.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | type mysqlResult struct { 12 | affectedRows int64 13 | insertId int64 14 | } 15 | 16 | func (res *mysqlResult) LastInsertId() (int64, error) { 17 | return res.insertId, nil 18 | } 19 | 20 | func (res *mysqlResult) RowsAffected() (int64, error) { 21 | return res.affectedRows, nil 22 | } 23 | -------------------------------------------------------------------------------- /vendor/github.com/go-sql-driver/mysql/transaction.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | type mysqlTx struct { 12 | mc *mysqlConn 13 | } 14 | 15 | func (tx *mysqlTx) Commit() (err error) { 16 | if tx.mc == nil || tx.mc.netConn == nil { 17 | return ErrInvalidConn 18 | } 19 | err = tx.mc.exec("COMMIT") 20 | tx.mc = nil 21 | return 22 | } 23 | 24 | func (tx *mysqlTx) Rollback() (err error) { 25 | if tx.mc == nil || tx.mc.netConn == nil { 26 | return ErrInvalidConn 27 | } 28 | err = tx.mc.exec("ROLLBACK") 29 | tx.mc = nil 30 | return 31 | } 32 | -------------------------------------------------------------------------------- /vendor/github.com/gorilla/context/README.md: -------------------------------------------------------------------------------- 1 | context 2 | ======= 3 | [![Build Status](https://travis-ci.org/gorilla/context.png?branch=master)](https://travis-ci.org/gorilla/context) 4 | 5 | gorilla/context is a general purpose registry for global request variables. 6 | 7 | Read the full documentation here: http://www.gorillatoolkit.org/pkg/context 8 | -------------------------------------------------------------------------------- /vendor/github.com/gorilla/mux/context_gorilla.go: -------------------------------------------------------------------------------- 1 | // +build !go1.7 2 | 3 | package mux 4 | 5 | import ( 6 | "net/http" 7 | 8 | "github.com/gorilla/context" 9 | ) 10 | 11 | func contextGet(r *http.Request, key interface{}) interface{} { 12 | return context.Get(r, key) 13 | } 14 | 15 | func contextSet(r *http.Request, key, val interface{}) *http.Request { 16 | if val == nil { 17 | return r 18 | } 19 | 20 | context.Set(r, key, val) 21 | return r 22 | } 23 | 24 | func contextClear(r *http.Request) { 25 | context.Clear(r) 26 | } 27 | -------------------------------------------------------------------------------- /vendor/github.com/gorilla/mux/context_native.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package mux 4 | 5 | import ( 6 | "context" 7 | "net/http" 8 | ) 9 | 10 | func contextGet(r *http.Request, key interface{}) interface{} { 11 | return r.Context().Value(key) 12 | } 13 | 14 | func contextSet(r *http.Request, key, val interface{}) *http.Request { 15 | if val == nil { 16 | return r 17 | } 18 | 19 | return r.WithContext(context.WithValue(r.Context(), key, val)) 20 | } 21 | 22 | func contextClear(r *http.Request) { 23 | return 24 | } 25 | -------------------------------------------------------------------------------- /vendor/github.com/gorilla/securecookie/fuzz.go: -------------------------------------------------------------------------------- 1 | // +build gofuzz 2 | 3 | package securecookie 4 | 5 | var hashKey = []byte("very-secret12345") 6 | var blockKey = []byte("a-lot-secret1234") 7 | var s = New(hashKey, blockKey) 8 | 9 | type Cookie struct { 10 | B bool 11 | I int 12 | S string 13 | } 14 | 15 | func Fuzz(data []byte) int { 16 | datas := string(data) 17 | var c Cookie 18 | if err := s.Decode("fuzz", datas, &c); err != nil { 19 | return 0 20 | } 21 | if _, err := s.Encode("fuzz", c); err != nil { 22 | panic(err) 23 | } 24 | return 1 25 | } 26 | -------------------------------------------------------------------------------- /vendor/github.com/imdario/mergo/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Dario Castañé. All rights reserved. 2 | // Copyright 2009 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | /* 7 | Package mergo merges same-type structs and maps by setting default values in zero-value fields. 8 | 9 | Mergo won't merge unexported (private) fields but will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection). 10 | 11 | Usage 12 | 13 | From my own work-in-progress project: 14 | 15 | type networkConfig struct { 16 | Protocol string 17 | Address string 18 | ServerType string `json: "server_type"` 19 | Port uint16 20 | } 21 | 22 | type FssnConfig struct { 23 | Network networkConfig 24 | } 25 | 26 | var fssnDefault = FssnConfig { 27 | networkConfig { 28 | "tcp", 29 | "127.0.0.1", 30 | "http", 31 | 31560, 32 | }, 33 | } 34 | 35 | // Inside a function [...] 36 | 37 | if err := mergo.Merge(&config, fssnDefault); err != nil { 38 | log.Fatal(err) 39 | } 40 | 41 | // More code [...] 42 | 43 | */ 44 | package mergo 45 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Go project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Go, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of Go. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of Go or any code incorporated within this 19 | implementation of Go constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of Go 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/html/charset/testdata/README: -------------------------------------------------------------------------------- 1 | These test cases come from 2 | http://www.w3.org/International/tests/repository/html5/the-input-byte-stream/results-basics 3 | 4 | Distributed under both the W3C Test Suite License 5 | (http://www.w3.org/Consortium/Legal/2008/04-testsuite-license) 6 | and the W3C 3-clause BSD License 7 | (http://www.w3.org/Consortium/Legal/2008/03-bsd-license). 8 | To contribute to a W3C Test Suite, see the policies and contribution 9 | forms (http://www.w3.org/2004/10/27-testcases). 10 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/html/charset/testdata/UTF-16BE-BOM.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/machine-intelligence/arbital-open-source/ce5ee1c472e39834fbd61b895ba23b501aa96e54/vendor/golang.org/x/net/html/charset/testdata/UTF-16BE-BOM.html -------------------------------------------------------------------------------- /vendor/golang.org/x/net/html/charset/testdata/UTF-16LE-BOM.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/machine-intelligence/arbital-open-source/ce5ee1c472e39834fbd61b895ba23b501aa96e54/vendor/golang.org/x/net/html/charset/testdata/UTF-16LE-BOM.html -------------------------------------------------------------------------------- /vendor/golang.org/x/net/html/entity_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package html 6 | 7 | import ( 8 | "testing" 9 | "unicode/utf8" 10 | ) 11 | 12 | func TestEntityLength(t *testing.T) { 13 | // We verify that the length of UTF-8 encoding of each value is <= 1 + len(key). 14 | // The +1 comes from the leading "&". This property implies that the length of 15 | // unescaped text is <= the length of escaped text. 16 | for k, v := range entity { 17 | if 1+len(k) < utf8.RuneLen(v) { 18 | t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v)) 19 | } 20 | if len(k) > longestEntityWithoutSemicolon && k[len(k)-1] != ';' { 21 | t.Errorf("entity name %s is %d characters, but longestEntityWithoutSemicolon=%d", k, len(k), longestEntityWithoutSemicolon) 22 | } 23 | } 24 | for k, v := range entity2 { 25 | if 1+len(k) < utf8.RuneLen(v[0])+utf8.RuneLen(v[1]) { 26 | t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v[0]) + string(v[1])) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/html/example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This example demonstrates parsing HTML data and walking the resulting tree. 6 | package html_test 7 | 8 | import ( 9 | "fmt" 10 | "log" 11 | "strings" 12 | 13 | "golang.org/x/net/html" 14 | ) 15 | 16 | func ExampleParse() { 17 | s := `

Links:

` 18 | doc, err := html.Parse(strings.NewReader(s)) 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | var f func(*html.Node) 23 | f = func(n *html.Node) { 24 | if n.Type == html.ElementNode && n.Data == "a" { 25 | for _, a := range n.Attr { 26 | if a.Key == "href" { 27 | fmt.Println(a.Val) 28 | break 29 | } 30 | } 31 | } 32 | for c := n.FirstChild; c != nil; c = c.NextSibling { 33 | f(c) 34 | } 35 | } 36 | f(doc) 37 | // Output: 38 | // foo 39 | // /bar/baz 40 | } 41 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/html/testdata/webkit/adoption02.dat: -------------------------------------------------------------------------------- 1 | #data 2 | 12

34 3 | #errors 4 | #document 5 | | 6 | | 7 | | 8 | | 9 | | "1" 10 | | 11 | | "2" 12 | | 13 | |

14 | | 15 | | "3" 16 | | "4" 17 | 18 | #data 19 |

20 | #errors 21 | #document 22 | | 23 | | 24 | | 25 | | 26 | |
27 | | 28 | |