Repository: microsoft/qsharp
Pull request #1805 (2024-07-30 21:56:12)

Update rust version to 1.80
This PR updates the versions in our build and release pipelines to use Rust 1.80.

When fixing the new clippy lints to satisfy 1.80, we get some errors in the build pipeline.

All of the errors are related to the fact that rust 1.80 implements Iterator for `&Box<[...]>`. So, what before had to be written as `for elt in container.iter()` now can be written as `for elt in container` which is more concise, and clippy enforces this new style.
 
`for elt in &**container` happens to be equivalent and it works both in rust 1.78 and rust 1.80, and clippy doesn't complain about it in either.
 
This PR changes all the instances of `for elt in container.iter()` where container is a `&Box<[...]>` to `for elt in &**container` so we can update the rust version to 1.80. There will be a subsequent PR that changes all the instances of `for elt in &**container` to `for elt in container`.

github-actions[bot]: ## Benchmark for e9e2219
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 339.0±3.35µs | 338.1±2.98µs | -0.27% |
| Array literal evaluation | **177.2±7.88µs** | 193.7±1.47µs | **+9.31%** |
| Array update evaluation | 415.6±1.68µs | **412.4±4.59µs** | **-0.77%** |
| Core + Standard library compilation | 26.2±1.16ms | 25.8±1.28ms | -1.53% |
| Deutsch-Jozsa evaluation | 5.0±0.07ms | 5.0±0.05ms | 0.00% |
| Large file parity evaluation | 34.1±0.18ms | 34.1±0.11ms | 0.00% |
| Large input file compilation | 15.0±0.61ms | 14.9±0.65ms | -0.67% |
| Large input file compilation (interpreter) | 58.4±2.28ms | 58.4±2.22ms | 0.00% |
| Large nested iteration | 33.1±0.21ms | **32.5±0.44ms** | **-1.81%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1628.0±140.79µs | 1624.4±141.84µs | -0.22% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 8.3±0.12ms | 8.3±0.14ms | 0.00% |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1495.1±212.82µs | 1480.4±137.73µs | -0.98% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 28.8±0.40ms | 28.8±0.46ms | 0.00% |
| Teleport evaluation | 92.0±3.49µs | 92.2±3.60µs | +0.22% |

  </details>
  
github-actions[bot]: ## Benchmark for a8e0c6e
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 339.7±3.44µs | 341.2±4.20µs | +0.44% |
| Array literal evaluation | 175.1±1.09µs | 174.9±0.99µs | -0.11% |
| Array update evaluation | **413.5±1.15µs** | 415.9±2.72µs | **+0.58%** |
| Core + Standard library compilation | 21.5±0.23ms | 21.5±0.26ms | 0.00% |
| Deutsch-Jozsa evaluation | 4.9±0.05ms | 4.9±0.06ms | 0.00% |
| Large file parity evaluation | 34.0±0.07ms | **33.9±0.11ms** | **-0.29%** |
| Large input file compilation | 12.9±0.23ms | 12.9±0.15ms | 0.00% |
| Large input file compilation (interpreter) | 50.7±1.07ms | 50.1±1.10ms | -1.18% |
| Large nested iteration | 33.0±0.17ms | 33.1±0.20ms | +0.30% |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1559.4±31.34µs | 1561.1±41.50µs | +0.11% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 7.8±0.12ms | **7.7±0.07ms** | **-1.28%** |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1424.1±56.72µs | 1422.3±32.95µs | -0.13% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 27.6±0.46ms | 27.6±0.14ms | 0.00% |
| Teleport evaluation | 91.9±3.50µs | 91.1±3.56µs | -0.87% |

  </details>
  

Patch:
diff --git a/.ado/publish.yml b/.ado/publish.yml
index c7c8b2bd..a57f531d 100644
--- a/.ado/publish.yml
+++ b/.ado/publish.yml
@@ -19,7 +19,7 @@ schedules:
 
 variables:
   CARGO_TERM_COLOR: always
-  RUST_TOOLCHAIN_VERSION: "1.78"
+  RUST_TOOLCHAIN_VERSION: "1.80"
 
 resources:
   repositories:
diff --git a/.github/workflows/bench-reports.yml b/.github/workflows/bench-reports.yml
index 24cde4f7..904c362a 100644
--- a/.github/workflows/bench-reports.yml
+++ b/.github/workflows/bench-reports.yml
@@ -15,7 +15,7 @@ env:
   CARGO_TERM_COLOR: always
   NODE_VERSION: "18.17.1"
   PYTHON_VERSION: "3.11"
-  RUST_TOOLCHAIN_VERSION: "1.78"
+  RUST_TOOLCHAIN_VERSION: "1.80"
   RUST_TOOLCHAIN_COMPONENTS: rustfmt clippy
 
 jobs:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2582a535..0a81ee97 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -20,7 +20,7 @@ env:
   CARGO_TERM_COLOR: always
   NODE_VERSION: "18.17.1"
   PYTHON_VERSION: "3.11"
-  RUST_TOOLCHAIN_VERSION: "1.78"
+  RUST_TOOLCHAIN_VERSION: "1.80"
   RUST_TOOLCHAIN_COMPONENTS: rustfmt clippy
 
 jobs:
diff --git a/.github/workflows/publish-playground.yml b/.github/workflows/publish-playground.yml
index 43859abd..27445454 100644
--- a/.github/workflows/publish-playground.yml
+++ b/.github/workflows/publish-playground.yml
@@ -11,7 +11,7 @@ on:
 
 env:
   CARGO_TERM_COLOR: always
-  RUST_TOOLCHAIN_VERSION: "1.78"
+  RUST_TOOLCHAIN_VERSION: "1.80"
   RUST_TOOLCHAIN_COMPONENTS: rustfmt clippy
 
 # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
diff --git a/Cargo.toml b/Cargo.toml
index bd3fbc87..d6f9149d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -77,7 +77,7 @@ tokio = { version = "1.35", features = ["macros", "rt"] }
 
 [workspace.lints.clippy]
 mod_module_files = "warn"
-pedantic = "warn"
+pedantic = { level = "warn", priority = -1 }
 unwrap_used = "warn"
 missing_errors_doc = "allow"
 missing_panics_doc = "allow"
diff --git a/compiler/qsc_ast/src/ast.rs b/compiler/qsc_ast/src/ast.rs
index 71582b08..d8448086 100644
--- a/compiler/qsc_ast/src/ast.rs
+++ b/compiler/qsc_ast/src/ast.rs
@@ -388,7 +388,7 @@ impl Display for TyDefKind {
                 } else {
                     write!(indent, "Tuple:")?;
                     indent = set_indentation(indent, 1);
-                    for t in ts.iter() {
+                    for t in &**ts {
                         write!(indent, "\n{t}")?;
                     }
                 }
@@ -531,7 +531,7 @@ impl Display for CallableBody {
                 let mut indent = set_indentation(indented(f), 0);
                 write!(indent, "Specializations:")?;
                 indent = set_indentation(indent, 1);
-                for spec in specs.iter() {
+                for spec in &**specs {
                     write!(indent, "\n{spec}")?;
                 }
             }
@@ -697,7 +697,7 @@ impl Display for TyKind {
                     indent = indent.with_format(Format::Uniform {
                         indentation: "    ",
                     });
-                    for t in ts.iter() {
+                    for t in &**ts {
                         write!(indent, "\n{t}")?;
                     }
                 }
@@ -1309,7 +1309,7 @@ impl Display for PatKind {
                 } else {
                     write!(indent, "Tuple:")?;
                     indent = set_indentation(indent, 1);
-                    for p in ps.iter() {
+                    for p in &**ps {
                         write!(indent, "\n{p}")?;
                     }
                 }
@@ -1380,7 +1380,7 @@ impl Display for QubitInitKind {
                 } else {
                     write!(indent, "Tuple:")?;
                     indent = set_indentation(indent, 1);
-                    for qi in qis.iter() {
+                    for qi in &**qis {
                         write!(indent, "\n{qi}")?;
                     }
                 }
@@ -1512,7 +1512,7 @@ impl Display for Idents {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         let mut buf = Vec::with_capacity(self.0.len());
 
-        for ident in self.0.iter() {
+        for ident in &*self.0 {
             buf.push(format!("{ident}"));
         }
         if buf.len() > 1 {
@@ -1595,7 +1595,7 @@ impl Idents {
             return self.0[0].name.clone();
         }
         let mut buf = String::new();
-        for ident in self.0.iter() {
+        for ident in &*self.0 {
             if !buf.is_empty() {
                 buf.push('.');
             }
diff --git a/compiler/qsc_ast/src/mut_visit.rs b/compiler/qsc_ast/src/mut_visit.rs
index 2ecb845c..cf2277c9 100644
--- a/compiler/qsc_ast/src/mut_visit.rs
+++ b/compiler/qsc_ast/src/mut_visit.rs
@@ -126,7 +126,7 @@ pub fn walk_item(vis: &mut impl MutVisitor, item: &mut Item) {
         ItemKind::Struct(decl) => vis.visit_struct_decl(decl),
         ItemKind::ImportOrExport(export) => {
             vis.visit_span(&mut export.span);
-            for item in export.items.iter_mut() {
+            for item in &mut *export.items {
                 vis.visit_path(&mut item.path);
                 if let Some(ref mut alias) = item.alias {
                     vis.visit_ident(alias);
@@ -389,7 +389,7 @@ pub fn walk_ident(vis: &mut impl MutVisitor, ident: &mut Ident) {
 }
 
 pub fn walk_idents(vis: &mut impl MutVisitor, ident: &mut crate::ast::Idents) {
-    for ref mut ident in ident.0.iter_mut() {
+    for ref mut ident in &mut *ident.0 {
         vis.visit_ident(ident);
     }
 }
diff --git a/compiler/qsc_ast/src/visit.rs b/compiler/qsc_ast/src/visit.rs
index cb2d1aa8..55376358 100644
--- a/compiler/qsc_ast/src/visit.rs
+++ b/compiler/qsc_ast/src/visit.rs
@@ -116,7 +116,7 @@ pub fn walk_item<'a>(vis: &mut impl Visitor<'a>, item: &'a Item) {
         }
         ItemKind::Struct(decl) => vis.visit_struct_decl(decl),
         ItemKind::ImportOrExport(decl) => {
-            for item in decl.items.iter() {
+            for item in &*decl.items {
                 vis.visit_path(&item.path);
                 if let Some(ref alias) = item.alias {
                     vis.visit_ident(alias);
diff --git a/compiler/qsc_codegen/src/qsharp.rs b/compiler/qsc_codegen/src/qsharp.rs
index 800f143e..3888cc25 100644
--- a/compiler/qsc_codegen/src/qsharp.rs
+++ b/compiler/qsc_codegen/src/qsharp.rs
@@ -176,7 +176,7 @@ impl<W: Write> Visitor<'_> for QSharpGen<W> {
     fn visit_ty_def(&mut self, def: &'_ TyDef) {
         match &*def.kind {
             TyDefKind::Field(name, ty) => {
-                for n in name {
+                if let Some(n) = name {
                     self.visit_ident(n);
                     self.write(": ");
                 }
@@ -479,7 +479,7 @@ impl<W: Write> Visitor<'_> for QSharpGen<W> {
                 self.visit_expr(cond);
                 self.write(" ");
                 self.visit_block(body);
-                for expr in otherwise {
+                if let Some(expr) = otherwise {
                     if matches!(*expr.kind, ExprKind::If(..)) {
                         // visiting expr as if writes 'if' to make 'elif'
                         self.write(" el");
@@ -610,7 +610,7 @@ impl<W: Write> Visitor<'_> for QSharpGen<W> {
                 self.visit_block(body);
                 self.write("until ");
                 self.visit_expr(until);
-                for fixup in fixup {
+                if let Some(fixup) = fixup {
                     self.write(" fixup ");
                     self.visit_block(fixup);
                 }
@@ -709,14 +709,14 @@ impl<W: Write> Visitor<'_> for QSharpGen<W> {
             PatKind::Bind(name, ty) => {
                 self.visit_ident(name);
 
-                for t in ty {
+                if let Some(t) = ty {
                     self.write(": ");
                     self.visit_ty(t);
                 }
             }
             PatKind::Discard(ty) => {
                 self.write("_");
-                for t in ty {
+                if let Some(t) = ty {
                     self.write(": ");
                     self.visit_ty(t);
                 }
diff --git a/compiler/qsc_doc_gen/src/display.rs b/compiler/qsc_doc_gen/src/display.rs
index 43856760..8588e6f5 100644
--- a/compiler/qsc_doc_gen/src/display.rs
+++ b/compiler/qsc_doc_gen/src/display.rs
@@ -643,7 +643,7 @@ fn ast_callable_functors(callable: &ast::CallableDecl) -> ty::FunctorSetValue {
         });
 
     if let ast::CallableBody::Specs(specs) = callable.body.as_ref() {
-        for spec in specs.iter() {
+        for spec in &**specs {
             let spec_functors = match spec.spec {
                 ast::Spec::Body => ty::FunctorSetValue::Empty,
                 ast::Spec::Adj => ty::FunctorSetValue::Adj,
@@ -678,7 +678,7 @@ fn as_struct(ty_def: &ast::TyDef) -> Option<Vec<ast::FieldDef>> {
         ast::TyDefKind::Paren(inner) => as_struct(inner),
         ast::TyDefKind::Tuple(fields) => {
             let mut converted_fields = Vec::new();
-            for field in fields.iter() {
+            for field in &**fields {
                 let field = remove_parens(field);
                 match field.kind.as_ref() {
                     ast::TyDefKind::Field(Some(name), field_ty) => {
diff --git a/compiler/qsc_frontend/src/incremental.rs b/compiler/qsc_frontend/src/incremental.rs
index 4935face..3d0e47be 100644
--- a/compiler/qsc_frontend/src/incremental.rs
+++ b/compiler/qsc_frontend/src/incremental.rs
@@ -372,7 +372,7 @@ impl Compiler {
         let offset = sources.push(source_name.into(), source_contents.into());
 
         let mut offsetter = Offsetter(offset);
-        for node in package.nodes.iter_mut() {
+        for node in &mut *package.nodes {
             match node {
                 ast::TopLevelNode::Namespace(ns) => offsetter.visit_namespace(ns),
                 ast::TopLevelNode::Stmt(stmt) => offsetter.visit_stmt(stmt),
diff --git a/compiler/qsc_frontend/src/lower.rs b/compiler/qsc_frontend/src/lower.rs
index a1033a76..fb4d4f57 100644
--- a/compiler/qsc_frontend/src/lower.rs
+++ b/compiler/qsc_frontend/src/lower.rs
@@ -200,7 +200,7 @@ impl With<'_> {
                 if item.is_import() {
                     return None;
                 }
-                for item in item.items.iter() {
+                for item in &*item.items {
                     let Some((id, alias)) = resolve_id(item.name().id) else {
                         continue;
                     };
diff --git a/compiler/qsc_frontend/src/resolve.rs b/compiler/qsc_frontend/src/resolve.rs
index a2dd49ca..6d732b10 100644
--- a/compiler/qsc_frontend/src/resolve.rs
+++ b/compiler/qsc_frontend/src/resolve.rs
@@ -1674,7 +1674,7 @@ fn bind_global_item(
             if decl.is_import() {
                 Ok(())
             } else {
-                for decl_item in decl.items.iter() {
+                for decl_item in &*decl.items {
                     // if the item is a namespace, bind it here as an item
                     let Some(ns) = scope
                         .namespaces
@@ -1832,6 +1832,7 @@ fn decl_is_intrinsic(decl: &CallableDecl) -> bool {
 /// - Next, we check open statements for a non-prelude open.
 /// - Then, we check the prelude.
 /// - Lastly, we check the global namespace.
+///
 /// In the example `Foo.Bar.Baz()` -- the `provided_namespace_name` would be
 ///`Foo.Bar` and the `provided_symbol_name` would be `Baz`.
 ///
@@ -1960,6 +1961,7 @@ fn check_all_scopes<'a>(
 /// 1. if any locally declared symbols match `provided_symbol_name`
 /// 2. if any aliases in this scope match the provided namespace, and if they contain `provided_symbol_name`
 /// 3. if any opens in this scope contain the `provided_symbol_name`
+///
 /// It follows the Q# shadowing rules:
 /// - Local variables shadow everything. They are the first priority.
 /// - Next, we check open statements for an explicit open.
@@ -2046,8 +2048,8 @@ fn check_scoped_resolutions(
 /// * `globals` - The global scope to resolve the name against.
 /// * `provided_symbol_name` - The symbol name that is ambiguous.
 /// * `candidates` - A map of possible resolutions for the symbol, each associated with the `Open`
-/// statement that brought it into scope. Note that only the first two opens in
-/// the candidates are actually used in the error message.
+///   statement that brought it into scope. Note that only the first two opens in
+///   the candidates are actually used in the error message.
 fn ambiguous_symbol_error(
     globals: &GlobalScope,
     provided_symbol_name: &Ident,
diff --git a/compiler/qsc_frontend/src/typeck/check.rs b/compiler/qsc_frontend/src/typeck/check.rs
index c0a96bb4..6eb2825e 100644
--- a/compiler/qsc_frontend/src/typeck/check.rs
+++ b/compiler/qsc_frontend/src/typeck/check.rs
@@ -171,7 +171,7 @@ impl Checker {
                 },
             ),
             ast::CallableBody::Specs(specs) => {
-                for spec in specs.iter() {
+                for spec in &**specs {
                     if let ast::SpecBody::Impl(input, block) = &spec.body {
                         self.check_spec(
                             names,
diff --git a/compiler/qsc_frontend/src/typeck/convert.rs b/compiler/qsc_frontend/src/typeck/convert.rs
index 71eaf317..65955cdd 100644
--- a/compiler/qsc_frontend/src/typeck/convert.rs
+++ b/compiler/qsc_frontend/src/typeck/convert.rs
@@ -54,7 +54,7 @@ pub(crate) fn ty_from_ast(names: &Names, ty: &ast::Ty) -> (Ty, Vec<MissingTyErro
         TyKind::Tuple(items) => {
             let mut tys = Vec::new();
             let mut errors = Vec::new();
-            for item in items.iter() {
+            for item in &**items {
                 let (item_ty, item_errors) = ty_from_ast(names, item);
                 tys.push(item_ty);
                 errors.extend(item_errors);
@@ -132,7 +132,7 @@ fn ast_ty_def_base(names: &Names, def: &TyDef) -> (Ty, Vec<MissingTyError>) {
         TyDefKind::Tuple(items) => {
             let mut tys = Vec::new();
             let mut errors = Vec::new();
-            for item in items.iter() {
+            for item in &**items {
                 let (item_ty, item_errors) = ast_ty_def_base(names, item);
                 tys.push(item_ty);
                 errors.extend(item_errors);
@@ -285,7 +285,7 @@ pub(crate) fn ast_pat_ty(names: &Names, pat: &Pat) -> (Ty, Vec<MissingTyError>)
         PatKind::Tuple(items) => {
             let mut tys = Vec::new();
             let mut errors = Vec::new();
-            for item in items.iter() {
+            for item in &**items {
                 let (item_ty, item_errors) = ast_pat_ty(names, item);
                 tys.push(item_ty);
                 errors.extend(item_errors);
@@ -303,7 +303,7 @@ pub(crate) fn ast_callable_functors(callable: &CallableDecl) -> FunctorSetValue
         .map_or(FunctorSetValue::Empty, |f| eval_functor_expr(f.as_ref()));
 
     if let CallableBody::Specs(specs) = callable.body.as_ref() {
-        for spec in specs.iter() {
+        for spec in &**specs {
             let spec_functors = match spec.spec {
                 Spec::Body => FunctorSetValue::Empty,
                 Spec::Adj => FunctorSetValue::Adj,
diff --git a/compiler/qsc_frontend/src/typeck/rules.rs b/compiler/qsc_frontend/src/typeck/rules.rs
index cb588e74..27ea2d18 100644
--- a/compiler/qsc_frontend/src/typeck/rules.rs
+++ b/compiler/qsc_frontend/src/typeck/rules.rs
@@ -342,7 +342,7 @@ impl<'a> Context<'a> {
             }
             ExprKind::Interpolate(components) => {
                 let mut diverges = false;
-                for component in components.iter() {
+                for component in &**components {
                     match component {
                         StringComponent::Expr(expr) => {
                             let span = expr.span;
@@ -465,7 +465,7 @@ impl<'a> Context<'a> {
                     self.inferrer.eq(copy.span, container.clone(), copy_ty.ty);
                 }
 
-                for field in fields.iter() {
+                for field in &**fields {
                     self.infer_field_assign(
                         field.span,
                         container.clone(),
@@ -499,7 +499,7 @@ impl<'a> Context<'a> {
             ExprKind::Tuple(items) => {
                 let mut tys = Vec::new();
                 let mut diverges = false;
-                for item in items.iter() {
+                for item in &**items {
                     let item = self.infer_expr(item);
                     diverges = diverges || item.diverges;
                     tys.push(item.ty);
@@ -626,7 +626,7 @@ impl<'a> Context<'a> {
             ExprKind::Tuple(items) => {
                 let mut tys = Vec::new();
                 let mut diverges = false;
-                for item in items.iter() {
+                for item in &**items {
                     let item = self.infer_hole_tuple(hole, given, tuple, to_ty, item);
                     diverges = diverges || item.diverges;
                     tys.push(item.ty);
@@ -847,7 +847,7 @@ impl<'a> Context<'a> {
             QubitInitKind::Tuple(items) => {
                 let mut diverges = false;
                 let mut tys = Vec::new();
-                for item in items.iter() {
+                for item in &**items {
                     let item = self.infer_qubit_init(item);
                     diverges = diverges || item.diverges;
                     tys.push(item.ty);
diff --git a/compiler/qsc_hir/src/hir.rs b/compiler/qsc_hir/src/hir.rs
index d47d2ba3..38dc4842 100644
--- a/compiler/qsc_hir/src/hir.rs
+++ b/compiler/qsc_hir/src/hir.rs
@@ -1233,7 +1233,7 @@ impl Display for Idents {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         let mut buf = Vec::with_capacity(self.0.len());
 
-        for ident in self.0.iter() {
+        for ident in &*self.0 {
             buf.push(format!("{ident}"));
         }
         if buf.len() > 1 {
@@ -1313,7 +1313,7 @@ impl Idents {
             return self.0[0].name.clone();
         }
         let mut buf = String::new();
-        for ident in self.0.iter() {
+        for ident in &*self.0 {
             if !buf.is_empty() {
                 buf.push('.');
             }
diff --git a/compiler/qsc_hir/src/mut_visit.rs b/compiler/qsc_hir/src/mut_visit.rs
index be3904a1..694b7272 100644
--- a/compiler/qsc_hir/src/mut_visit.rs
+++ b/compiler/qsc_hir/src/mut_visit.rs
@@ -248,7 +248,7 @@ pub fn walk_ident(vis: &mut impl MutVisitor, ident: &mut Ident) {
 }
 
 pub fn walk_idents(vis: &mut impl MutVisitor, ident: &mut crate::hir::Idents) {
-    for ref mut ident in ident.0.iter_mut() {
+    for ref mut ident in &mut *ident.0 {
         vis.visit_ident(ident);
     }
 }
diff --git a/compiler/qsc_linter/src/linter/ast.rs b/compiler/qsc_linter/src/linter/ast.rs
index d375a0ad..8ef1d2c9 100644
--- a/compiler/qsc_linter/src/linter/ast.rs
+++ b/compiler/qsc_linter/src/linter/ast.rs
@@ -31,7 +31,7 @@ pub fn run_ast_lints(package: &qsc_ast::ast::Package, config: Option<&[LintConfi
 
     let mut lints = CombinedAstLints::from_config(config);
 
-    for node in package.nodes.iter() {
+    for node in &*package.nodes {
         match node {
             TopLevelNode::Namespace(namespace) => lints.visit_namespace(namespace),
             TopLevelNode::Stmt(stmt) => lints.visit_stmt(stmt),
diff --git a/compiler/qsc_linter/src/lints/ast.rs b/compiler/qsc_linter/src/lints/ast.rs
index 42363872..41483207 100644
--- a/compiler/qsc_linter/src/lints/ast.rs
+++ b/compiler/qsc_linter/src/lints/ast.rs
@@ -130,7 +130,7 @@ impl AstLintPass for RedundantSemicolons {
         // Some(_): one or more redundant semicolons
         let mut seq: Option<Span> = None;
 
-        for stmt in block.stmts.iter() {
+        for stmt in &*block.stmts {
             match (&*stmt.kind, &mut seq) {
                 (StmtKind::Empty, None) => seq = Some(stmt.span),
                 (StmtKind::Empty, Some(span)) => span.hi = stmt.span.hi,
diff --git a/compiler/qsc_parse/src/item.rs b/compiler/qsc_parse/src/item.rs
index 1ea772b5..e358b46b 100644
--- a/compiler/qsc_parse/src/item.rs
+++ b/compiler/qsc_parse/src/item.rs
@@ -151,6 +151,7 @@ pub fn parse_implicit_namespace(source_name: &str, s: &mut ParserContext) -> Res
     }
     let lo = s.peek().span.lo;
     let items = parse_namespace_block_contents(s)?;
+    recovering_token(s, TokenKind::Eof);
     if items.is_empty() || s.peek().kind != TokenKind::Eof {
         return Err(Error(ErrorKind::ExpectedItem(s.peek().kind, s.span(lo))));
     }
@@ -370,7 +371,7 @@ fn try_tydef_as_ty(tydef: &TyDef) -> Option<Ty> {
         TyDefKind::Paren(tydef) => try_tydef_as_ty(tydef.as_ref()),
         TyDefKind::Tuple(tup) => {
             let mut ty_tup = Vec::new();
-            for tydef in tup.iter() {
+            for tydef in &**tup {
                 ty_tup.push(try_tydef_as_ty(tydef)?);
             }
             Some(Ty {
diff --git a/compiler/qsc_rir/src/passes/reindex_qubits.rs b/compiler/qsc_rir/src/passes/reindex_qubits.rs
index 6a9e21ca..a305f966 100644
--- a/compiler/qsc_rir/src/passes/reindex_qubits.rs
+++ b/compiler/qsc_rir/src/passes/reindex_qubits.rs
@@ -28,6 +28,7 @@ struct BlockQubitMap {
 /// 1. Only one callable has a body, which is the entry point callable.
 /// 2. The entry point callable is a directed acyclic graph where block ids have topological ordering.
 /// 3. No dynamic qubits are used.
+///
 /// The pass will panic if the input program violates any of these assumptions.
 pub fn reindex_qubits(program: &mut Program) {
     validate_assumptions(program);
diff --git a/katas/content/complex_arithmetic/cartesian_to_polar/index.md b/katas/content/complex_arithmetic/cartesian_to_polar/index.md
index 30cf726c..951420bf 100644
--- a/katas/content/complex_arithmetic/cartesian_to_polar/index.md
+++ b/katas/content/complex_arithmetic/cartesian_to_polar/index.md
@@ -2,7 +2,7 @@
 A complex number $x = a + bi$.
 
 **Goal:**
-Return the polar representation of $x = re^{i\theta}$, i.e., the distance from origin $r$ and phase $\theta$ as a `ComplexPolar`.
+Return the polar representation of $x = re^{i\theta}$, that is, the distance from origin $r$ and phase $\theta$ as a `ComplexPolar`.
 
 * $r$ should be non-negative: $r \geq 0$
 * $\theta$ should be between $-\pi$ and $\pi$: $-\pi < \theta \leq \pi$
diff --git a/katas/content/complex_arithmetic/cartesian_to_polar/solution.md b/katas/content/complex_arithmetic/cartesian_to_polar/solution.md
index 641f9b4c..2af0179f 100644
--- a/katas/content/complex_arithmetic/cartesian_to_polar/solution.md
+++ b/katas/content/complex_arithmetic/cartesian_to_polar/solution.md
@@ -1,9 +1,9 @@
-We need to calculate the $r$ and $\theta$ values as seen in the complex plane. 
+You need to calculate the $r$ and $\theta$ values as seen in the complex plane. 
 $r$ should be familiar to you already, since it is the modulus of a number (exercise 6):
 
 $$ r = \sqrt{a^2 + b^2} $$
 
-$\theta$ can be calculated using trigonometry: since we know that the polar and the Cartesian forms of the number represent the same value, we can write
+$\theta$ can be calculated using trigonometry: since you know that the polar and the Cartesian forms of the number represent the same value, you can write
 
 $$ re^{i \theta} = a + bi $$
 
@@ -11,11 +11,11 @@ Euler's formula allows us to express the left part of the equation as
 
 $$ re^{i \theta} = r \cos \theta + i r \sin \theta $$
 
-For two complex numbers to be equal, their real and imaginary parts have to be equal. This gives us the following system of equations:
+For two complex numbers to be equal, their real and imaginary parts have to be equal. This gives you the following system of equations:
 
 $$ \begin{cases} a = r \cos \theta \\ b = r \sin \theta \end{cases} $$
 
-To calculate $\theta$, we can divide the second equation by the first one to get
+To calculate $\theta$, you can divide the second equation by the first one to get
 
 $$ \tan \theta = \frac{b}{a} $$
 
diff --git a/katas/content/complex_arithmetic/complex_exponents/solution.md b/katas/content/complex_arithmetic/complex_exponents/solution.md
index d3a9a240..cd63a4ef 100644
--- a/katas/content/complex_arithmetic/complex_exponents/solution.md
+++ b/katas/content/complex_arithmetic/complex_exponents/solution.md
@@ -1,4 +1,4 @@
-To start, we will rewrite the expression $e^{a + bi}$ as a product of two simpler expressions: $ e^a \cdot\ e^{bi} $.
+To start, you'll rewrite the expression $e^{a + bi}$ as a product of two simpler expressions: $ e^a \cdot\ e^{bi} $.
 The first part is a real number.
 The second part can be expressed using the formula $e^{i\theta} = \cos \theta + i\sin \theta$.
 Substituting this into our expression gives:
diff --git a/katas/content/complex_arithmetic/complex_powers_real/solution.md b/katas/content/complex_arithmetic/complex_powers_real/solution.md
index a6f2eb88..df227458 100644
--- a/katas/content/complex_arithmetic/complex_powers_real/solution.md
+++ b/katas/content/complex_arithmetic/complex_powers_real/solution.md
@@ -1,14 +1,14 @@
-Rewrite the expression $r^x$ to use Euler's constant, which will allow us to use an approach similar to the solution to the previous exercise.
+Rewrite the expression $r^x$ to use Euler's constant, which will allow you to use an approach similar to the solution to the previous exercise.
 
 First, rewrite $r^x$ into a product of two powers: $$ r^{a+bi} = r^a \cdot r^{bi} $$
 
-Given that $r = e^{\ln r} $ ($\ln$ is the natural logarithm), we can rewrite the second part of the product as follows: 
+Given that $r = e^{\ln r} $ ($\ln$ is the natural logarithm), you can rewrite the second part of the product as follows: 
     $$ r^{bi} =  e^{bi\ln r} $$
 
-Now, given $e^{i\theta} = \cos \theta + i\sin \theta$, we can rewrite it further as follows: 
+Now, given $e^{i\theta} = \cos \theta + i\sin \theta$, you can rewrite it further as follows: 
     $$ e^{bi\ln r} = \cos( b \cdot \ln r) + i \sin(b \cdot \ln r) $$
 
-When substituting this into the original expression, we get:
+When substituting this into the original expression, you get:
     $$ \underset{real}{\underbrace{r^a \cos(b \cdot \ln r)}} + \underset{imaginary}{\underbrace{r^a \sin(b \cdot \ln r)}} i $$
 
 @[solution]({"id": "complex_arithmetic__complex_powers_real_solution", "codePath": "Solution.qs"})
diff --git a/katas/content/complex_arithmetic/index.md b/katas/content/complex_arithmetic/index.md
index 3f969ced..0c500b81 100644
--- a/katas/content/complex_arithmetic/index.md
+++ b/katas/content/complex_arithmetic/index.md
@@ -18,7 +18,7 @@ This kata introduces you to complex arithmetic. This topic isn't particularly ex
 
 If you are curious to learn more, you can find more information at [Wikipedia](https://en.wikipedia.org/wiki/Complex_number).
 
-This kata has several tasks that require you to write Q# code to test your understanding of the concepts. It will introduce the necessary Q# language constructs as it goes.
+This kata has several tasks that require you to write Q# code to test your understanding of the concepts. The kata will introduce the necessary Q# language constructs as it goes.
 
 @[section]({ 
     "id": "complex_arithmetic__algebraic_perspective", 
@@ -29,11 +29,11 @@ For some purposes, real numbers aren't enough. Probably the most famous example
 
 $$x^{2} = -1$$
 
-This equation has no solution among real numbers. If, however, we abandon that constraint, we can do something interesting - we can define our own number. Let's say there exists some number that solves that equation. Let's call that number $i$.
+This equation has no solution among real numbers. But if you abandon that constraint, you can do something interesting - you can define your own number. Let's say there exists some number that solves that equation. Let's call that number $i$.
 
 $$i^2 = -1$$
 
-As we said before, $i$ can't be a real number. In that case, we'll call it an **imaginary unit**. However, there is no reason for us to define it as acting any different from any other number, other than the fact that $i^2 = -1$:
+As said before, the number $i$ can't be a real number. In that case, let's call it an **imaginary number**. However, there's no reason to define it as acting any different from any other number, other than the fact that $i^2 = -1$. This means that you can do all the same operations on $i$ that you can do on any other number. For example:
 
 $$i+i=2i$$
 
@@ -43,7 +43,7 @@ $$-1 \cdot i=-i$$
 
 $$(-i)^{2} = -1$$
 
-We'll call the number $i$ and its real multiples (numbers obtained by multiplying $i$ by a real number) **imaginary numbers**.
+The number $i$ and its real multiples (numbers obtained by multiplying $i$ by a real number) are called **imaginary numbers**.
 
 > A good video introduction to imaginary numbers can be found [here](https://youtu.be/SP-YJe7Vldo).
 
@@ -58,13 +58,13 @@ We'll call the number $i$ and its real multiples (numbers obtained by multiplyin
     "title": "Complex Numbers" 
 })
 
-Adding imaginary numbers to each other is quite simple, but what happens when we add a real number to an imaginary number? The result of that addition will be partly real and partly imaginary, otherwise known as a **complex number**. A complex number is simply the real part and the imaginary part being treated as a single number. Complex numbers are generally written as the sum of their two parts $a$ and $bi$, where both $a$ and $b$ are real numbers: 
+Adding imaginary numbers to each other is quite simple, but what happens when you add a real number to an imaginary number? The result of that addition will be partly real and partly imaginary, otherwise known as a **complex number**. A complex number is simply the real part and the imaginary part being treated as a single number. Complex numbers are generally written as the sum of their two parts $a$ and $bi$, where both $a$ and $b$ are real numbers: 
 
 $$a+bi$$
 
 For example, $3+4i$ or $-5-7i$ are valid complex numbers. Note that purely real or purely imaginary numbers can also be written as complex numbers: $2$ is $2+0i$, and $-3i$ is $0-3i$.
 
-When performing operations on complex numbers, it is often helpful to treat them as polynomials in terms of $i$.
+When performing operations on complex numbers, it's often helpful to treat them as polynomials in terms of $i$.
 Let's see how to do the main arithmetic operations on complex numbers.
 
 > In Q#, complex numbers are represented as user-defined type `Complex` from the `Microsoft.Quantum.Math` namespace. 
@@ -91,9 +91,9 @@ Let's see how to do the main arithmetic operations on complex numbers.
     "title": "Complex Conjugate" 
 })
 
-Before we discuss any other operations on complex numbers, we have to cover the **complex conjugate**. The conjugate is a simple operation: given a complex number  $x = a + bi$, its complex conjugate is $\overline{x} = a - bi$.
+Before discussing any other operations on complex numbers, let's review the **complex conjugate**. The conjugate is a simple operation: given a complex number  $x = a + bi$, its complex conjugate is $\overline{x} = a - bi$.
 
-The conjugate allows us to do some interesting things. The first and probably most important is multiplying a complex number by its conjugate:
+The conjugate allows you to do some interesting things. The first and probably most important is multiplying a complex number by its conjugate:
 
 $$x \cdot \overline{x} = (a + bi)(a - bi)$$
 
@@ -125,11 +125,11 @@ Let's expand $x$ and $y$ into their component forms:
 
 $$\frac{x}{y} = \frac{a + bi}{c + di}$$
 
-Unfortunately, it isn't very clear what it means to divide by a complex number. We need some way to move either all real parts or all imaginary parts into the numerator. And thanks to the conjugate, we can do just that. Using the fact that any number (except $0$) divided by itself equals $1$, and any number multiplied by $1$ equals itself, we get:
+Unfortunately, it isn't very clear what it means to divide by a complex number. You need some way to move either all real parts or all imaginary parts into the numerator. And thanks to the conjugate, you can do just that. Using the fact that any number (except $0$) divided by itself equals $1$, and any number multiplied by $1$ equals itself, you get:
 
 $$\frac{x}{y} = \frac{x}{y} \cdot 1 = \frac{x}{y} \cdot \frac{\overline{y}}{\overline{y}} = \frac{x\overline{y}}{y\overline{y}} = \frac{(a + bi)(c - di)}{(c + di)(c - di)} = \frac{(a + bi)(c - di)}{c^2 + d^2}$$
 
-By doing this, we re-wrote our division problem to have a complex multiplication expression in the numerator, and a real number in the denominator. We already know how to multiply complex numbers, and dividing a complex number by a real number is as simple as dividing both parts of the complex number separately:
+By doing this, you re-wrote your division problem to have a complex multiplication expression in the numerator, and a real number in the denominator. You already know how to multiply complex numbers, and dividing a complex number by a real number is as simple as dividing both parts of the complex number separately:
 
 $$\frac{a + bi}{r} = \frac{a}{r} + \frac{b}{r}i$$
 
@@ -144,11 +144,11 @@ $$\frac{a + bi}{r} = \frac{a}{r} + \frac{b}{r}i$$
     "title": "Geometric Perspective: the Complex Plane" 
 })
 
-You may recall that real numbers can be represented geometrically using the number line - a line on which each point represents a real number. We can extend this representation to include imaginary and complex numbers, which gives rise to an entirely different number line: the imaginary number line, which is orthogonal to the real number line and only intersects with it at $0$.
+You may recall that real numbers can be represented geometrically using the number line - a line on which each point represents a real number. You can extend this representation to include imaginary and complex numbers, which gives rise to an entirely different number line: the imaginary number line, which is orthogonal to the real number line and only intersects with it at $0$.
 
-A complex number has two components - a real component and an imaginary component. As you no doubt noticed from the exercises, these can be represented by two real numbers - the real component, and the real coefficient of the imaginary component. This allows us to map complex numbers onto a two-dimensional plane - the **complex plane**. The most common mapping is the obvious one: $a+bi$ can be represented by the point $(a,b)$ in the **Cartesian coordinate system**.
+A complex number has two components - a real component and an imaginary component. As you no doubt noticed from the exercises, these can be represented by two real numbers - the real component, and the real coefficient of the imaginary component. This allows you to map complex numbers onto a two-dimensional plane - the **complex plane**. The most common mapping is the obvious one: $a+bi$ can be represented by the point $(a,b)$ in the **Cartesian coordinate system**.
 
-This mapping allows us to apply complex arithmetic to geometry, and, more importantly, apply geometric concepts to complex numbers. Many properties of complex numbers become easier to understand when viewed through a geometric lens.
+This mapping allows you to apply complex arithmetic to geometry, and, more importantly, apply geometric concepts to complex numbers. Many properties of complex numbers become easier to understand when viewed through a geometric lens.
 
 ## Modulus
 
@@ -179,7 +179,7 @@ $$|x + y| \leq |x| + |y|$$
     "title": "Imaginary Exponents" 
 })
 
-The next complex operation we're going to need is exponentiation. Raising an imaginary number to an integer power is a fairly simple task, but raising a number to an imaginary power, or raising an imaginary (or complex) number to a real power isn't quite as simple.
+The next complex operation is **exponentiation**. Raising an imaginary number to an integer power is a fairly simple task, but raising a number to an imaginary power, or raising an imaginary (or complex) number to a real power isn't quite as simple.
 
 Let's start with raising real numbers to imaginary powers. Specifically, let's start with a rather special real number - Euler's constant, $e$:
 
@@ -187,7 +187,7 @@ $$e^{i\theta} = \cos \theta + i\sin \theta$$
 
 Here and later in this tutorial $\theta$ is measured in radians.
 
-> Explaining why that happens is somewhat beyond the scope of this tutorial, as it requires some calculus, so we won't do that here. If you are curious, you can see [this video](https://youtu.be/v0YEaeIClKY) for a beautiful intuitive explanation, or [this Wikipedia article](https://en.wikipedia.org/wiki/Complex_number) for a more mathematically rigorous proof.
+> Explaining why that happens is beyond the scope of this tutorial. If you are curious, you can see [this video](https://youtu.be/v0YEaeIClKY) for a beautiful intuitive explanation, or [this Wikipedia article](https://en.wikipedia.org/wiki/Complex_number) for a more mathematically rigorous proof.
 
 Here are some examples of this formula in action:
 
@@ -200,13 +200,13 @@ $$e^{2i\pi} = 1$$
 > 
 > $$e^{i\pi} + 1 = 0$$
 > 
-> While this doesn't have any notable uses, it is still an interesting identity to consider, as it combines five fundamental constants of algebra into one expression.
+> While this doesn't have any notable uses, it's still an interesting identity to consider, as it combines five fundamental constants of algebra into one expression.
 
-We can also calculate complex powers of $e$ as follows:
+You can also calculate complex powers of $e$ as follows:
 
 $$e^{a + bi} = e^a \cdot e^{bi}$$
 
-Finally, using logarithms to express the base of the exponent as $r = e^{\ln r}$, we can use this to find complex powers of any positive real number.
+Finally, using logarithms to express the base of the exponent as $r = e^{\ln r}$, you can use this to find complex powers of any positive real number.
 
 @[exercise]({ 
     "id": "complex_arithmetic__complex_exponents_exercise", 
@@ -225,11 +225,11 @@ Finally, using logarithms to express the base of the exponent as $r = e^{\ln r}$
     "title": "Polar Coordinates" 
 })
 
-Consider the expression  $e^{i\theta} = \cos\theta + i\sin\theta$. Notice that if we map this number onto the complex plane, it will land on a **unit circle** around $0 + 0i$. This means that its modulus is always $1$. You can also verify this algebraically: $\cos^2\theta + \sin^2\theta = 1$.
+Consider the expression  $e^{i\theta} = \cos\theta + i\sin\theta$. Notice that if you map this number onto the complex plane, it'll land on a **unit circle** around $0 + 0i$. This means that its modulus is always $1$. You can also verify this algebraically: $\cos^2\theta + \sin^2\theta = 1$.
 
-Using this fact we can represent complex numbers using **polar coordinates**. In a polar coordinate system, a point is represented by two numbers: its direction from origin, represented by an angle from the $x$ axis, and how far away it is in that direction.
+Using this fact you can represent complex numbers using **polar coordinates**. In a polar coordinate system, a point is represented by two numbers: its direction from origin, represented by an angle from the $x$ axis, and how far away it is in that direction.
 
-Another way to think about this is that we're taking a point that is $1$ unit away (which is on the unit circle) in the specified direction, and multiplying it by the desired distance. And to get the point on the unit circle, we can use $e^{i\theta}$.
+Another way to think about this is that you're taking a point that is $1$ unit away (which is on the unit circle) in the specified direction, and multiplying it by the desired distance. And to get the point on the unit circle, you can use $e^{i\theta}$.
 
 A complex number of the format $r \cdot e^{i\theta}$ will be represented by a point which is $r$ units away from the origin, in the direction specified by the angle $\theta$.
 Sometimes $\theta$ will be referred to as the number's **argument** or **phase**.
diff --git a/katas/content/complex_arithmetic/polar_multiplication/solution.md b/katas/content/complex_arithmetic/polar_multiplication/solution.md
index 3dabd237..8a38e4b0 100644
--- a/katas/content/complex_arithmetic/polar_multiplication/solution.md
+++ b/katas/content/complex_arithmetic/polar_multiplication/solution.md
@@ -8,7 +8,7 @@ $$ z = x \cdot y = r_{1}e^{\theta_1 i} \cdot r_{2}e^{\theta_2 i} = r_{1}r_{2} \c
 > $$ z = x \cdot y = r_1r_2 \cdot \left( \cos \theta_1 \cos \theta_2 − \sin \theta_1 \sin \theta_2 + 
 i (\sin \theta_1 \cos \theta_2 + \sin \theta_2 \cos \theta_1 ) \right) $$
 >
-> We can simplify this using the following trigonometric identities:
+> You can simplify this using the following trigonometric identities:
 > * $\cos a \cos b  \mp \sin a \sin b = \cos(a \pm b)$
 > * $\sin a \cos b  \pm \sin b \cos a = \sin(a \pm b)$
 >
diff --git a/katas/content/complex_arithmetic/polar_to_cartesian/solution.md b/katas/content/complex_arithmetic/polar_to_cartesian/solution.md
index 17a0a34d..008b67a4 100644
--- a/katas/content/complex_arithmetic/polar_to_cartesian/solution.md
+++ b/katas/content/complex_arithmetic/polar_to_cartesian/solution.md
@@ -1,4 +1,4 @@
-Euler's formula allows us to express the complex polar number as 
+Euler's formula allows you to express the complex polar number as 
 
 $$ re^{i \theta} = \underset{real}{\underbrace{r \cos \theta}} + i \underset{imaginary}{\underbrace{r \sin \theta}}$$
 
diff --git a/katas/content/complex_arithmetic/powers_of_i/solution.md b/katas/content/complex_arithmetic/powers_of_i/solution.md
index 19b3a405..a7813206 100644
--- a/katas/content/complex_arithmetic/powers_of_i/solution.md
+++ b/katas/content/complex_arithmetic/powers_of_i/solution.md
@@ -6,7 +6,7 @@ $$i^4 = i^2 \cdot i^2 = (-1) \cdot (-1) = 1$$
 Thus, when the exponent $n$ is divisible by 4, $i^n$ will always be 1.
 
 When the exponent $n$ is not divisible by 4, you can use the previous observation to see that $i^n = i^{n \mod 4}$.
-For an even exponent $n$ that is not divisible by 4 you'll have $i^n = i^2 = -1.$
+For an even exponent $n$ that isn't divisible by 4 you'll have $i^n = i^2 = -1.$
 
 Here is the complete pattern that arises when raising $i$ to non-negative powers. Note that it is periodic with period $4$.
 
diff --git a/katas/content/index.json b/katas/content/index.json
index 9fa7d004..8047a149 100644
--- a/katas/content/index.json
+++ b/katas/content/index.json
@@ -21,5 +21,7 @@
   "deutsch_jozsa",
   "grovers_search",
   "solving_sat",
+  "solving_graph_coloring",
+  "qft",
   "qec_shor"
 ]
diff --git a/katas/content/multi_qubit_systems/index.md b/katas/content/multi_qubit_systems/index.md
index f56de7ec..e487e1d1 100644
--- a/katas/content/multi_qubit_systems/index.md
+++ b/katas/content/multi_qubit_systems/index.md
@@ -318,7 +318,7 @@ If they are not in zero state by that time, they can potentially be still entang
 In the following exercises you will learn to prepare separable quantum states by manipulating individual qubits.
 You will only need knowledge from the Single-Qubit Gates kata for that.
 
-> In each exercise, you'll be given an array of qubits to manipulate; you can access $i$-th element of the array `qs` as `qs[i]`.
+> In each exercise, you'll be given an array of qubits to manipulate; you can access the $i$-th element of the array `qs` as `qs[i]`.
 Array elements are indexed starting with 0, the first array element corresponds to the leftmost qubit in Dirac notation.
 
 @[exercise]({
diff --git a/katas/content/nonlocal_games/chsh_classical_strategy/Verification.qs b/katas/content/nonlocal_games/chsh_classical_strategy/Verification.qs
index d407458d..8526baa4 100644
--- a/katas/content/nonlocal_games/chsh_classical_strategy/Verification.qs
+++ b/katas/content/nonlocal_games/chsh_classical_strategy/Verification.qs
@@ -6,8 +6,8 @@ namespace Kata.Verification {
     operation CheckSolution() : Bool {
         mutable wins = 0;
         for i in 1..1000 {
-            let x = DrawRandomInt(0, 1) == 1 ? true | false;
-            let y = DrawRandomInt(0, 1) == 1 ? true | false;
+            let x = DrawRandomBool(0.5);
+            let y = DrawRandomBool(0.5);
             let (a, b) = (Kata.AliceClassical(x), Kata.BobClassical(y));
             if ((x and y) == (a != b)) {
                 set wins = wins + 1;
diff --git a/katas/content/nonlocal_games/chsh_classical_win_condition/index.md b/katas/content/nonlocal_games/chsh_classical_win_condition/index.md
index 4485f2f5..bacc5942 100644
--- a/katas/content/nonlocal_games/chsh_classical_win_condition/index.md
+++ b/katas/content/nonlocal_games/chsh_classical_win_condition/index.md
@@ -1,6 +1,7 @@
 **Input:** 
-* Alice and Bob's starting bits (X and Y).
-* Alice and Bob's output bits (A and B).
+
+- Alice and Bob's starting bits (X and Y).
+- Alice and Bob's output bits (A and B).
 
 **Output:**
   True if Alice and Bob won the CHSH game, that is, if X ∧ Y = A ⊕ B, and false otherwise.
diff --git a/katas/content/nonlocal_games/chsh_quantum_alice_strategy/Placeholder.qs b/katas/content/nonlocal_games/chsh_quantum_alice_strategy/Placeholder.qs
new file mode 100644
index 00000000..9aecfc25
--- /dev/null
+++ b/katas/content/nonlocal_games/chsh_quantum_alice_strategy/Placeholder.qs
@@ -0,0 +1,7 @@
+namespace Kata {
+    operation AliceQuantum (bit : Bool, qubit : Qubit) : Bool {
+        // Implement your solution here...
+
+        return false;
+    }
+}
diff --git a/katas/content/nonlocal_games/chsh_quantum_alice_strategy/Solution.qs b/katas/content/nonlocal_games/chsh_quantum_alice_strategy/Solution.qs
new file mode 100644
index 00000000..96a6f61e
--- /dev/null
+++ b/katas/content/nonlocal_games/chsh_quantum_alice_strategy/Solution.qs
@@ -0,0 +1,12 @@
+namespace Kata {
+    operation AliceQuantum (bit : Bool, qubit : Qubit) : Bool {
+        if bit {
+            let q = MResetX(qubit);
+            return q == One;
+        }
+        else {
+            let q = MResetZ(qubit);
+            return q == One;
+        }
+    }
+}
diff --git a/katas/content/nonlocal_games/chsh_quantum_alice_strategy/Verification.qs b/katas/content/nonlocal_games/chsh_quantum_alice_strategy/Verification.qs
new file mode 100644
index 00000000..d1554e79
--- /dev/null
+++ b/katas/content/nonlocal_games/chsh_quantum_alice_strategy/Verification.qs
@@ -0,0 +1,49 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Convert;
+    open Microsoft.Quantum.Random;
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        use q = Qubit();
+        for _ in 1 .. 4 {
+            // repeat 4 times since we are testing a measurement and wrong basis still might get
+            // the correct answer, reduces probability of false positives
+            let result = Kata.AliceQuantum(false, q);
+            Reset(q);
+            if (result != false) {
+                Message("Measuring |0⟩ in the Z basis returned incorrect value; expected false");
+                return false;
+            }
+
+            // apply the Pauli X gate
+            X(q);
+            let result = Kata.AliceQuantum(false, q);
+            Reset(q);
+            if (result != true) {
+                Message("Measuring |1⟩ in the Z basis returned incorrect value; expected true");
+                return false;
+            }
+
+            // apply the Hadamard gate
+            H(q);
+            let result = Kata.AliceQuantum(true, q);
+            Reset(q);
+            if (result != false) {
+                Message("Measuring |+⟩ in the X basis returned incorrect value; expected false");
+                return false;
+            }
+
+            // apply the Pauli X and then the Hadamard gate
+            X(q);
+            H(q);
+            let result = Kata.AliceQuantum(true, q);
+            Reset(q);
+            if (result != true) {
+                Message("Measuring |-⟩ in the X basis returned incorrect value; expected true");
+                return false;
+            }
+        }
+        Message("Correct!");
+        true
+    }
+}
diff --git a/katas/content/nonlocal_games/chsh_quantum_alice_strategy/index.md b/katas/content/nonlocal_games/chsh_quantum_alice_strategy/index.md
new file mode 100644
index 00000000..fc442e2d
--- /dev/null
+++ b/katas/content/nonlocal_games/chsh_quantum_alice_strategy/index.md
@@ -0,0 +1,12 @@
+In the quantum version of the game, the players still can not communicate during the game,
+but they are allowed to share qubits from a Bell pair before the start of the game.
+
+**Inputs:**
+
+- Alice's starting bit (X).
+- Alice's half of Bell pair she shares with Bob.
+
+**Goal:**
+  Measure Alice's qubit in the Z basis if her bit is 0 (false), or the X basis if her bit is 1 (true) and
+  return the measurement result as Boolean value: map `Zero` to false and `One` to true.
+  The state of the qubit after the operation does not matter.
diff --git a/katas/content/nonlocal_games/chsh_quantum_alice_strategy/solution.md b/katas/content/nonlocal_games/chsh_quantum_alice_strategy/solution.md
new file mode 100644
index 00000000..64bbd830
--- /dev/null
+++ b/katas/content/nonlocal_games/chsh_quantum_alice_strategy/solution.md
@@ -0,0 +1,12 @@
+In Q#, you can perform measurements in a specific basis using either the
+[Measure operation](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.intrinsic/measure)
+or convenient shorthands for measure-and-reset-to-$\ket{0}$ sequence of operations
+[MResetZ](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.measurement/mresetz) and
+[MResetX](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.measurement/mresetx).
+
+(See the the lesson below for details on why Alice should follow this strategy.)
+
+@[solution]({
+    "id": "nonlocal_games__chsh_quantum_alice_strategy_solution",
+    "codePath": "Solution.qs"
+})
diff --git a/katas/content/nonlocal_games/chsh_quantum_bob_strategy/Placeholder.qs b/katas/content/nonlocal_games/chsh_quantum_bob_strategy/Placeholder.qs
new file mode 100644
index 00000000..2477ed5a
--- /dev/null
+++ b/katas/content/nonlocal_games/chsh_quantum_bob_strategy/Placeholder.qs
@@ -0,0 +1,9 @@
+namespace Kata {
+    open Microsoft.Quantum.Math;
+
+    operation BobQuantum (bit : Bool, qubit : Qubit) : Bool {
+        // Implement your solution here...
+
+        return false;
+    }
+}
diff --git a/katas/content/nonlocal_games/chsh_quantum_bob_strategy/Solution.qs b/katas/content/nonlocal_games/chsh_quantum_bob_strategy/Solution.qs
new file mode 100644
index 00000000..ba690fe5
--- /dev/null
+++ b/katas/content/nonlocal_games/chsh_quantum_bob_strategy/Solution.qs
@@ -0,0 +1,9 @@
+namespace Kata {
+    open Microsoft.Quantum.Math;
+
+    operation BobQuantum (bit : Bool, qubit : Qubit) : Bool {
+        let angle = 2.0 * PI() / 8.0;
+        Ry(not bit ? -angle | angle, qubit);
+        return M(qubit) == One;
+    }
+}
diff --git a/katas/content/nonlocal_games/chsh_quantum_bob_strategy/Verification.qs b/katas/content/nonlocal_games/chsh_quantum_bob_strategy/Verification.qs
new file mode 100644
index 00000000..1d35fd08
--- /dev/null
+++ b/katas/content/nonlocal_games/chsh_quantum_bob_strategy/Verification.qs
@@ -0,0 +1,55 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Math;
+
+    operation RotateBobQubit (clockwise : Bool, qubit : Qubit) : Unit {
+        if (clockwise) {
+            Ry(-PI()/4.0, qubit);
+        } else {
+            Ry(PI()/4.0, qubit);
+        }
+    }
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        for _ in 1 .. 4 {
+            // repeat 4 times since we are testing a measurement and wrong basis still might get
+            // the correct answer, reduces probability of false positives
+            use q = Qubit();
+            RotateBobQubit(false, q);
+            let result = Kata.BobQuantum(false, q);
+            Reset(q);
+            if (result != false) {
+                Message("π/8 from |0⟩ not measured as false");
+                return false;
+            }
+
+            X(q);
+            RotateBobQubit(false, q);
+            let result = Kata.BobQuantum(false, q);
+            Reset(q);
+            if (result != true) {
+                Message("π/8 from |1⟩ not measured as true");
+                return false;
+            }
+
+            RotateBobQubit(true, q);
+            let result = Kata.BobQuantum(true, q);
+            Reset(q);
+            if (result != false) {
+                Message("-π/8 from |0⟩ not measured as false");
+                return false;
+            }
+
+            X(q);
+            RotateBobQubit(true, q);
+            let result = Kata.BobQuantum(true, q);
+            Reset(q);
+            if (result != true) {
+                Message("-π/8 from |1⟩ not measured as true");
+                return false;
+            }
+        }
+        Message("Correct!");
+        true
+    }   
+}
diff --git a/katas/content/nonlocal_games/chsh_quantum_bob_strategy/index.md b/katas/content/nonlocal_games/chsh_quantum_bob_strategy/index.md
new file mode 100644
index 00000000..a7b96bb7
--- /dev/null
+++ b/katas/content/nonlocal_games/chsh_quantum_bob_strategy/index.md
@@ -0,0 +1,11 @@
+**Inputs:**
+
+- Bob's starting bit (Y).
+- Bob's half of Bell pair he shares with Alice.
+
+**Goal:**
+Measure Bob's qubit in the $\frac{\pi}{8}$ basis if his bit is 0 (false), or the $-\frac{\pi}{8}$ basis
+if his bit is 1 (true) and return the measurement result as a Boolean value: map `Zero` to false and `One` to true.
+The state of the qubit after the operation does not matter.
+
+Measuring a qubit in the $\theta$ basis is the same as rotating the qubit by $\theta$, clockwise, and then making a standard measurement in the Z basis.
diff --git a/katas/content/nonlocal_games/chsh_quantum_bob_strategy/solution.md b/katas/content/nonlocal_games/chsh_quantum_bob_strategy/solution.md
new file mode 100644
index 00000000..a7841d51
--- /dev/null
+++ b/katas/content/nonlocal_games/chsh_quantum_bob_strategy/solution.md
@@ -0,0 +1,11 @@
+A suitable $R_y$ rotation can be used to go from the computational basis $\{ \ket{0}, \ket{1} \}$ to the $\{ \ket{\psi_+}, \ket{\psi_-} \}$ basis and vice versa.
+
+To implement the described transformation in Q#, we need to rotate the qubit by $\frac{\pi}{8}$ clockwise if `bit == false` or counterclockwise if `bit == true` and then perform a measurement.
+We can do the rotation using the $R_y$ gate (note the negation of the Boolean parameter we need to do).
+
+(See the lesson below for details on why Bob should follow this strategy.)
+
+@[solution]({
+    "id": "nonlocal_games__chsh_quantum_bob_strategy_solution",
+    "codePath": "Solution.qs"
+})
diff --git a/katas/content/nonlocal_games/examples/CHSHGameDemo.qs b/katas/content/nonlocal_games/examples/CHSHGameDemo.qs
new file mode 100644
index 00000000..b062f35b
--- /dev/null
+++ b/katas/content/nonlocal_games/examples/CHSHGameDemo.qs
@@ -0,0 +1,52 @@
+namespace Quantum.Kata.CHSHGame {
+    open Microsoft.Quantum.Random;
+    open Microsoft.Quantum.Math;
+    open Microsoft.Quantum.Convert;
+
+    function WinCondition (x : Bool, y : Bool, a : Bool, b : Bool) : Bool {
+        return (x and y) == (a != b);
+    }
+
+    function AliceClassical (x : Bool) : Bool {
+        return false;
+    }
+
+    function BobClassical (y : Bool) : Bool {
+        return false;
+    }
+
+    operation AliceQuantum (bit : Bool, qubit : Qubit) : Bool {
+        if bit {
+            return MResetX(qubit) == One;
+        }
+        return MResetZ(qubit) == One;
+    }
+
+    operation BobQuantum (bit : Bool, qubit : Qubit) : Bool {
+        let angle = 2.0 * PI() / 8.0;
+        Ry(not bit ? -angle | angle, qubit);
+        return M(qubit) == One;
+    }
+
+    @EntryPoint()
+    operation CHSH_GameDemo() : Unit {
+        use (aliceQubit, bobQubit) = (Qubit(), Qubit());
+        mutable classicalWins = 0;
+        mutable quantumWins = 0;
+        let iterations = 1000;
+        for _ in 1 .. iterations {
+            H(aliceQubit);
+            CNOT(aliceQubit, bobQubit);
+            let (x, y) = (DrawRandomBool(0.5), DrawRandomBool(0.5));
+            if WinCondition(x, y, AliceClassical(x), BobClassical(y)) {
+                set classicalWins += 1;
+            }
+            if WinCondition(x, y, AliceQuantum(x, aliceQubit), BobQuantum(y, bobQubit)) {
+                set quantumWins += 1;
+            }
+            ResetAll([aliceQubit, bobQubit]);
+        }
+        Message($"Percentage of classical wins is {100.0*IntAsDouble(classicalWins)/IntAsDouble(iterations)}%");
+        Message($"Percentage of quantum wins is {100.0*IntAsDouble(quantumWins)/IntAsDouble(iterations)}%");
+    }
+}
diff --git a/katas/content/nonlocal_games/index.md b/katas/content/nonlocal_games/index.md
index f81c1970..8d1ba9b4 100644
--- a/katas/content/nonlocal_games/index.md
+++ b/katas/content/nonlocal_games/index.md
@@ -12,13 +12,15 @@ so they cannot communicate with each other during the game.
 Another characteristics of these games is that they are "refereed", which means the players try to win against the referee.
 
 **This kata covers the following topics:**
- - Clauser, Horne, Shimony, and Hold thought experiment (often abbreviated as CHSH game)
- - Greenberger-Horne-Zeilinger game (often abbreviated as GHZ game)
- - The Mermin-Peres Magic Square game
+
+- Clauser, Horne, Shimony, and Hold thought experiment (often abbreviated as CHSH game)
+- Greenberger-Horne-Zeilinger game (often abbreviated as GHZ game)
+- The Mermin-Peres Magic Square game
 
 **What you should know to start working on this kata:**
- - Basic linear algebra
- - Basic knowledge of quantum gates and measurements
+
+- Basic linear algebra
+- Basic knowledge of quantum gates and measurements
 
 @[section]({
     "id": "nonlocal_games__chsh_game",
@@ -31,15 +33,11 @@ Each of them is given a bit (Alice gets X and Bob gets Y), and
 they have to return new bits (Alice returns A and Bob returns B)
 so that X ∧ Y = A ⊕ B. The trick is, they can not communicate during the game.
 
-> * ∧ is the standard bitwise AND operator.
-> * ⊕ is the exclusive or, or XOR operator, so (P ⊕ Q) is true if exactly one of P and Q is true.
-
-@[section]({
-    "id": "nonlocal_games__chsh_game_classical",
-    "title": "Part I. Classical CHSH"
-})
+> - ∧ is the standard bitwise AND operator.
+> - ⊕ is the exclusive or, or XOR operator, so (P ⊕ Q) is true if exactly one of P and Q is true.
 
 To start with, let's take a look at how you would play the classical variant of this game without access to any quantum tools.
+Then, let's proceed with quantum strategies for Alice and Bob.
 
 @[exercise]({
     "id": "nonlocal_games__chsh_classical_win_condition",
@@ -53,9 +51,147 @@ To start with, let's take a look at how you would play the classical variant of
     "path": "./chsh_classical_strategy/"
 })
 
+@[exercise]({
+    "id": "nonlocal_games__chsh_quantum_alice_strategy",
+    "title": "Alice's Quantum Strategy",
+    "path": "./chsh_quantum_alice_strategy/"
+})
+
+@[exercise]({
+    "id": "nonlocal_games__chsh_quantum_bob_strategy",
+    "title": "Bob's Quantum Strategy",
+    "path": "./chsh_quantum_bob_strategy/"
+})
+
+@[section]({
+    "id": "nonlocal_games__discussion",
+    "title": "Discussion: Probability of Victory for Quantum Strategy"
+})
+
+The above quantum strategy adopted by Alice and Bob offers a win rate of $\frac{2 + \sqrt{2}}{4}$, or about $85.36\%$. Let's see why this is the case.
+
+First, consider the outcome if Alice and Bob simply measure their qubits in the Z basis without manipulating them at all. Because of the entanglement inherent to the Bell state they hold, their measurements will always agree (i.e., both true or both false).
+This will suffice for victory in the three scenarios (0,0), (0,1) and (1,0) and fail for (1,1), so their win probability is $75\%$, the same as that for the straightforward classical strategies of invariably returning both true or both false.
+
+Now let's analyze the optimal quantum strategy.
+
+> As a reminder, probability "wavefunction" for a two-qubit state is given by the following length-4 vector of amplitudes:
+> $$\begin{bmatrix}\psi_{00}\\\psi_{01}\\\psi_{10}\\\psi_{11}\end{bmatrix}$$
+> $|\psi_{ij}|^2$ gives the probability of observing the corresponding basis state $\ket{ij}$ upon measuring the qubit pair.
+
+The initial state $\ket{00}$ has $\psi_{00} = 1$ and $\psi_{01} = \psi_{10} = \psi_{11} = 0$.
+The Bell state we prepare as the first step of the game has an amplitude vector as follows (we'll use decimal approximations for matrix elements):
+
+$$\begin{bmatrix}1/\sqrt{2}\\0\\0\\1/\sqrt{2}\end{bmatrix} = \begin{bmatrix}0.7071\\0\\0\\0.7071\end{bmatrix}$$
+
+Let's analyze the probabilities of outcomes in case of different bits received by players.
+
+## Case 1: Alice holds bit 0
+
+In this case Alice simply measures in the Z basis as above.
+
+- When Bob's bit is 0, he rotates his qubit clockwise by $\pi/8$, which corresponds to the operator
+
+$$\begin{bmatrix}
+    0.9239 & 0.3827 & 0 & 0\\
+    -0.3827 & 0.9239 & 0 & 0\\
+    0 & 0 & 0.9239 & 0.3827\\
+    0 & 0 & -0.3827 & 0.9239
+\end{bmatrix}$$
+This performs the $R_y$ rotation by $\pi/8$ radians clockwise on Bob's qubit while leaving Alice's qubit unchanged.
+
+- If Bob's bit were 1, he would rotate his qubit counterclockwise by $\pi/8$, applying a very similar operator
+
+$$\begin{bmatrix}
+    0.9239 & -0.3827 & 0 & 0\\
+    0.3827 & 0.9239 & 0 & 0\\
+    0 & 0 & 0.9239 & -0.3827\\
+    0 & 0 & 0.3827 & 0.9239
+\end{bmatrix}$$
+
+Therefore, when Alice has bit 0, the application of the rotation operator to the Bell state gives
+$$\begin{bmatrix}
+    0.6533 \\
+    -0.2706 \\
+    0.2706 \\
+    0.6533
+\end{bmatrix} \text{ or }
+\begin{bmatrix}
+    0.6533\\
+    0.2706\\
+    -0.2706\\
+    0.6533
+\end{bmatrix}$$
+depending on whether Bob holds 0 (left-hand case) or 1 (right-hand case).
+
+The result of AND on their input bits will always be 0; thus they win when their outputs agree.  These two cases correspond to the top and bottom elements of the vectors above, with a combined probability of $(0.6533)^2 + (0.6533)^2 = 0.4268 + 0.4268 = 0.8536$, so they have an $85.36\%$ win chance.
+
+## Case 2: Alice holds bit 1
+
+When Alice holds bit 1, she measures in basis X (or, equivalently, Hadamard-transforms her qubit, leaving Bob's qubit unchanged,
+before making her Z-basis measurement).  This corresponds to applying the operator
+$$\begin{bmatrix}
+    0.7071 & 0 & 0.7071 & 0\\
+    0 & 0.7071 & 0 & 0.7071\\
+    0.7071 & 0 & -0.7071 & 0\\
+    0 & 0.7071 & 0 & -0.7071
+\end{bmatrix}$$
+to the Bell state, resulting in a vector of:
+$$\begin{bmatrix}
+    0.5\\
+    0.5\\
+    0.5\\
+    -0.5
+\end{bmatrix}$$
+
+Now, one of the two rotation operators is applied depending on what bit Bob holds, transforming this vector into:
+$$\begin{bmatrix}
+    0.6533 \\
+    0.2706 \\
+    0.2706 \\
+    -0.6533
+\end{bmatrix} \text{ or }
+\begin{bmatrix}
+    0.2706\\
+    0.6533\\
+    0.6533\\
+    -0.2706
+    \end{bmatrix}$$
+
+When Bob holds 0, they still want to return the same parity, which they again do with $85.36\%$ probability (left-hand vector above).
+But when Bob holds 1, the AND condition is now true and the players want to answer in opposite parity. This corresponds to the second and third elements of the right-hand vector above.
+Thanks to the "magic" of the combination of the counterclockwise rotation and Hadamard transform, they now do this with probability $(0.6533)^2 + (0.6533)^2 = 0.8536$ and thus $85.36\%$ becomes their win odds once more.
+
+## Side notes
+
+- If Bob never rotated his qubit, their entangled state would remain the Bell state if Alice held bit 0 and the state corresponding to $\frac12 \big(\ket{00} + \ket{01} + \ket{10} - \ket{11}\big)$ if Alice held bit 1.
+While she and Bob would have a $100\%$ success probability against Alice's 0 bit, they would have only a $50\%$ chance of success if she held bit 1, and thus their win chance would revert to the $75\%$ of the classical strategy again.
+- It can be proven that Alice and Bob cannot surpass an overall win probability of $85.36\%$ in the CHSH game. This entails a higher-level discussion of quantum observable theory, for instance see [Tsirelson's bound](https://en.wikipedia.org/wiki/Tsirelson's_bound).
+
+@[section]({
+    "id": "nonlocal_games__chsh_e2e",
+    "title": "Running CHSH Game End to End"
+})
+
+Putting together the building blocks we've implemented into a strategy is very simple:
+- Allocate two qubits and prepare a Bell state on them.
+- Send one of the qubits to Alice and another to Bob (this step is "virtual", not directly reflected in Q# code, other than making sure that Alice and Bob each act on their qubit only).
+- Have Alice and Bob perform their measurements on their respective qubits using `AliceQuantum` and `BobQuantum` operations.
+- Reset used qubits to $\ket{0}$ before they are released.
+- Return their measurement results.
+
+In the example below you can compare winning percentage of classical and quantum games.
+
+>You may play with the code and check if there is a difference in results when
+>1. The referee picks non-random bits. How can the referee minimize Alice and Bob's win probability?
+>2. Bob's qubit is measured first.
+>3. Alice and Bob get unentangled qubit pair.
+
+@[example]({"id": "nonlocal_games__chsh_e2edemo", "codePath": "./examples/CHSHGameDemo.qs"})
+
 @[section]({
-    "id": "nonlocal_games__conclusion", 
-    "title": "Conclusion" 
+    "id": "nonlocal_games__conclusion",
+    "title": "Conclusion"
 })
 
 Congratulations! In this kata you learned how to use quantum entanglement in nonlocal quantum games to get results that are better than any classical strategy can offer.
diff --git a/katas/content/qft/all_basis_vectors/Placeholder.qs b/katas/content/qft/all_basis_vectors/Placeholder.qs
new file mode 100644
index 00000000..a90df6b8
--- /dev/null
+++ b/katas/content/qft/all_basis_vectors/Placeholder.qs
@@ -0,0 +1,14 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+
+    operation AllBasisVectors(qs : Qubit[]) : Unit is Adj + Ctl {
+        // Implement your solution here...
+
+    }
+
+    // You might find this helper operation that implements QFT using a library operation useful.
+    operation QFT(qs : Qubit[]) : Unit is Adj + Ctl {
+        ApplyQFT(Reversed(qs));
+        SwapReverseRegister(qs);
+    }
+}
diff --git a/katas/content/qft/all_basis_vectors/Solution.qs b/katas/content/qft/all_basis_vectors/Solution.qs
new file mode 100644
index 00000000..9f5a9e51
--- /dev/null
+++ b/katas/content/qft/all_basis_vectors/Solution.qs
@@ -0,0 +1,12 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+
+    operation AllBasisVectors(qs : Qubit[]) : Unit is Adj + Ctl {
+        QFT(qs);
+    }
+
+    operation QFT(qs : Qubit[]) : Unit is Adj + Ctl {
+        ApplyQFT(Reversed(qs));
+        SwapReverseRegister(qs);
+    }
+}
diff --git a/katas/content/qft/all_basis_vectors/Verification.qs b/katas/content/qft/all_basis_vectors/Verification.qs
new file mode 100644
index 00000000..849b58b2
--- /dev/null
+++ b/katas/content/qft/all_basis_vectors/Verification.qs
@@ -0,0 +1,25 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Katas;
+
+    operation AllBasisVectors_Reference (qs : Qubit[]) : Unit is Adj + Ctl {
+        for q in qs {
+            H(q);
+        }
+    }
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        for n in 1 .. 5 {
+            let solution = Kata.AllBasisVectors;
+            let reference = AllBasisVectors_Reference;
+            if not CheckOperationsEquivalenceOnZeroState(solution, reference, n) {
+                Message($"Incorrect for {n} qubit(s)");
+                ShowQuantumStateComparison(n, qs => (), solution, reference);
+                return false;
+            }
+        }
+
+        Message("Correct!");
+        return true;
+    }
+}
diff --git a/katas/content/qft/all_basis_vectors/index.md b/katas/content/qft/all_basis_vectors/index.md
new file mode 100644
index 00000000..bdb9b43b
--- /dev/null
+++ b/katas/content/qft/all_basis_vectors/index.md
@@ -0,0 +1,3 @@
+**Input:** $n$ qubits in the $\ket{0 \dots 0}$ state.
+
+**Goal:**  Change the state of the qubits to an equal superposition of all basis vectors $\frac{1}{\sqrt{2^N}} \big (\ket{0 \dots 0} + \dots + \ket{1 \dots 1}\big)$. 
diff --git a/katas/content/qft/all_basis_vectors/solution.md b/katas/content/qft/all_basis_vectors/solution.md
new file mode 100644
index 00000000..3416fde8
--- /dev/null
+++ b/katas/content/qft/all_basis_vectors/solution.md
@@ -0,0 +1,10 @@
+You can think of the required equal superposition of all basis states as the QFT of the state $\ket{0...0}$. Indeed, if $j_1 = j_2 = ... = j_n = 0$, $j = 0$, and you get the following state:
+
+$$\frac1{\sqrt{2^n}} \sum_{k=0}^{2^n-1} e^{2\pi i \cdot \frac{jk}{2^{n}}} \ket{k} = \frac{1}{\sqrt{2^n}} \sum_{k=0}^{2^n-1} e^{0} \ket{k} = \frac{1}{\sqrt{2^n}} \sum_{k=0}^{2^n-1} \ket{k}$$
+
+This means that you can solve this task by simply applying the QFT to the given qubit register.
+
+@[solution]({
+    "id": "qft__all_basis_vectors_solution",
+    "codePath": "./Solution.qs"
+})
diff --git a/katas/content/qft/all_even_vectors/Placeholder.qs b/katas/content/qft/all_even_vectors/Placeholder.qs
new file mode 100644
index 00000000..ded143f3
--- /dev/null
+++ b/katas/content/qft/all_even_vectors/Placeholder.qs
@@ -0,0 +1,14 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+
+    operation AllEvenVectors(qs : Qubit[]) : Unit is Adj + Ctl {
+        // Implement your solution here...
+
+    }
+
+    // You might find this helper operation that implements QFT using a library operation useful.
+    operation QFT(qs : Qubit[]) : Unit is Adj + Ctl {
+        ApplyQFT(Reversed(qs));
+        SwapReverseRegister(qs);
+    }
+}
diff --git a/katas/content/qft/all_even_vectors/Solution.qs b/katas/content/qft/all_even_vectors/Solution.qs
new file mode 100644
index 00000000..5129bbb2
--- /dev/null
+++ b/katas/content/qft/all_even_vectors/Solution.qs
@@ -0,0 +1,13 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+
+    operation AllEvenVectors(qs : Qubit[]) : Unit is Adj + Ctl {
+        H(qs[0]);
+        QFT(qs);
+    }
+
+    operation QFT(qs : Qubit[]) : Unit is Adj + Ctl {
+        ApplyQFT(Reversed(qs));
+        SwapReverseRegister(qs);
+    }
+}
diff --git a/katas/content/qft/all_even_vectors/Verification.qs b/katas/content/qft/all_even_vectors/Verification.qs
new file mode 100644
index 00000000..999dc0b0
--- /dev/null
+++ b/katas/content/qft/all_even_vectors/Verification.qs
@@ -0,0 +1,25 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Katas;
+
+    operation AllEvenVectors_Reference (qs : Qubit[]) : Unit is Adj + Ctl {
+        for q in qs[...Length(qs) - 2] {
+            H(q);
+        }
+    }
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        for n in 1 .. 5 {
+            let solution = Kata.AllEvenVectors;
+            let reference = AllEvenVectors_Reference;
+            if not CheckOperationsEquivalenceOnZeroState(solution, reference, n) {
+                Message($"Incorrect for {n} qubit(s)");
+                ShowQuantumStateComparison(n, qs => (), solution, reference);
+                return false;
+            }
+        }
+
+        Message("Correct!");
+        return true;
+    }
+}
diff --git a/katas/content/qft/all_even_vectors/index.md b/katas/content/qft/all_even_vectors/index.md
new file mode 100644
index 00000000..1bba41dc
--- /dev/null
+++ b/katas/content/qft/all_even_vectors/index.md
@@ -0,0 +1,13 @@
+**Input:** $n$ qubits in the $\ket{0 \dots 0}$ state.
+
+**Goal:**  Change the state of the qubits to an equal superposition of all even basis vectors:
+
+$$\frac1{\sqrt{2^{n-1}}} \big(\ket{0} + \ket{2} + ... + \ket{2^n-2} \big)$$
+
+> For example, for $n = 2$ the goal state is $\frac1{\sqrt2} \big(\ket{0} + \ket{2}\big)$.
+
+<details>
+  <summary><b>Need a hint?</b></summary>
+    Which superposition of two basis states can be mapped to this state using QFT?
+    Use the solutions to earlier tasks in this lesson to figure out the answer.
+</details>
\ No newline at end of file
diff --git a/katas/content/qft/all_even_vectors/solution.md b/katas/content/qft/all_even_vectors/solution.md
new file mode 100644
index 00000000..5c610aee
--- /dev/null
+++ b/katas/content/qft/all_even_vectors/solution.md
@@ -0,0 +1,21 @@
+You can see that the even superposition of two states from the first and the third tasks in this lesson will give the desired result. Indeed,
+
+$$\frac1{\sqrt{2^{n-1}}} \big(\ket{0} + \ket{2} + ... + \ket{2^n-2}\big) =$$
+$$=\frac{1}{\sqrt{2}} \bigg( \frac1{\sqrt{2^n}} \big(\ket{0} - \ket{1} + \ket{2} - \ket{3} + ... - \ket{2^n-1}\big) + \frac1{\sqrt{2^n}} \big(\ket{0} + \ket{1} + \ket{2} + \ket{3} + ... + \ket{2^n-1}\big)\bigg)$$
+
+Now, you can use the fact that QFT is a linear transformation.
+The two periodic states from earlier tasks are created by applying the QFT to the states $\ket{100...0}$ and $\ket{000...0}$ state. 
+To prepare an equal superposition of these two states, you can apply a Hadamard gate to the first qubit in the register:
+
+$$ \frac1{\sqrt2} \big(\ket{0} + \ket{1}\big) \otimes \ket{00...0} $$
+
+Then you apply QFT to the register: 
+
+$$ QFT\big(\frac1{\sqrt2} (\ket{0} + \ket{1}) \otimes \ket{00...0}\big) = \frac1{\sqrt2} \big( QFT\ket{000...0} + QFT\ket{100...0}\big)$$
+
+This results in the desired end state. 
+
+@[solution]({
+    "id": "qft__all_even_vectors_solution",
+    "codePath": "./Solution.qs"
+})
diff --git a/katas/content/qft/alternating_amplitudes/Placeholder.qs b/katas/content/qft/alternating_amplitudes/Placeholder.qs
new file mode 100644
index 00000000..8155987d
--- /dev/null
+++ b/katas/content/qft/alternating_amplitudes/Placeholder.qs
@@ -0,0 +1,14 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+
+    operation AlternatingAmplitudes(qs : Qubit[]) : Unit is Adj + Ctl {
+        // Implement your solution here...
+
+    }
+
+    // You might find this helper operation that implements QFT using a library operation useful.
+    operation QFT(qs : Qubit[]) : Unit is Adj + Ctl {
+        ApplyQFT(Reversed(qs));
+        SwapReverseRegister(qs);
+    }
+}
diff --git a/katas/content/qft/alternating_amplitudes/Solution.qs b/katas/content/qft/alternating_amplitudes/Solution.qs
new file mode 100644
index 00000000..34e0e677
--- /dev/null
+++ b/katas/content/qft/alternating_amplitudes/Solution.qs
@@ -0,0 +1,13 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+
+    operation AlternatingAmplitudes(qs : Qubit[]) : Unit is Adj + Ctl {
+        X(qs[0]);
+        QFT(qs);
+    }
+
+    operation QFT(qs : Qubit[]) : Unit is Adj + Ctl {
+        ApplyQFT(Reversed(qs));
+        SwapReverseRegister(qs);
+    }
+}
diff --git a/katas/content/qft/alternating_amplitudes/Verification.qs b/katas/content/qft/alternating_amplitudes/Verification.qs
new file mode 100644
index 00000000..cf4b46db
--- /dev/null
+++ b/katas/content/qft/alternating_amplitudes/Verification.qs
@@ -0,0 +1,26 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Katas;
+
+    operation AlternatingAmplitudes_Reference (qs : Qubit[]) : Unit is Adj + Ctl {
+        for q in qs {
+            H(q);
+        }
+        Z(qs[Length(qs) - 1]);
+    }
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        for n in 1 .. 5 {
+            let solution = Kata.AlternatingAmplitudes;
+            let reference = AlternatingAmplitudes_Reference;
+            if not CheckOperationsEquivalenceOnZeroState(solution, reference, n) {
+                Message($"Incorrect for {n} qubit(s)");
+                ShowQuantumStateComparison(n, qs => (), solution, reference);
+                return false;
+            }
+        }
+
+        Message("Correct!");
+        return true;
+    }
+}
diff --git a/katas/content/qft/alternating_amplitudes/index.md b/katas/content/qft/alternating_amplitudes/index.md
new file mode 100644
index 00000000..fe1ef543
--- /dev/null
+++ b/katas/content/qft/alternating_amplitudes/index.md
@@ -0,0 +1,7 @@
+**Input:** $n$ qubits in the $\ket{0 \dots 0}$ state.
+
+**Goal:**  Change the state of the qubits to a periodic state with alternating $1$ and $-1$ amplitudes of basis states:
+
+$$\frac1{\sqrt{2^n}} \big(\ket{0} - \ket{1} + \ket{2} - \ket{3} + ... - \ket{2^n-1} \big)$$
+
+> For example, for $n = 2$ the goal state is $\frac12 \big(\ket{0} - \ket{1} + \ket{2} - \ket{3}\big)$.
\ No newline at end of file
diff --git a/katas/content/qft/alternating_amplitudes/solution.md b/katas/content/qft/alternating_amplitudes/solution.md
new file mode 100644
index 00000000..97444353
--- /dev/null
+++ b/katas/content/qft/alternating_amplitudes/solution.md
@@ -0,0 +1,10 @@
+Since the amplitudes of this state have no imaginary parts, it is clear that the value of exponents for an arbitrary amplitude $e^{2\pi i \cdot \frac{Fk}{2^n}}$ must be either $2\pi i$ to get an amplitude equal $1$ or $\pi i$ for an amplitude of $-1$. 
+This means that only $j_1$ can be $1$: all other bits of $F$ must be $0$. 
+Indeed, you can check that using $F = 10...0 = 2^{n - 1}$ with the solution of the previous task yields the required state.
+
+You can simplify preparing this state: instead of using the general encoding of $F$ in the register, you can apply an $X$ gate to the first qubit of the register.
+
+@[solution]({
+    "id": "qft__alternating_amplitudes_solution",
+    "codePath": "./Solution.qs"
+})
diff --git a/katas/content/qft/binary_fraction_classical/Placeholder.qs b/katas/content/qft/binary_fraction_classical/Placeholder.qs
new file mode 100644
index 00000000..e0fb6b14
--- /dev/null
+++ b/katas/content/qft/binary_fraction_classical/Placeholder.qs
@@ -0,0 +1,6 @@
+namespace Kata {
+    operation BinaryFractionClassical(q : Qubit, j : Bool[]) : Unit is Adj + Ctl {
+        // Implement your solution here...
+     
+    }
+}
diff --git a/katas/content/qft/binary_fraction_classical/SolutionA.qs b/katas/content/qft/binary_fraction_classical/SolutionA.qs
new file mode 100644
index 00000000..37881dab
--- /dev/null
+++ b/katas/content/qft/binary_fraction_classical/SolutionA.qs
@@ -0,0 +1,9 @@
+namespace Kata {
+    operation BinaryFractionClassical(q : Qubit, j : Bool[]) : Unit is Adj + Ctl {
+        for ind in 0 .. Length(j) - 1 {
+            if j[ind] {
+                R1Frac(2, ind + 1, q);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/katas/content/qft/binary_fraction_classical/SolutionB.qs b/katas/content/qft/binary_fraction_classical/SolutionB.qs
new file mode 100644
index 00000000..91c055c5
--- /dev/null
+++ b/katas/content/qft/binary_fraction_classical/SolutionB.qs
@@ -0,0 +1,11 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+    open Microsoft.Quantum.Convert;
+    open Microsoft.Quantum.Math;
+
+    operation BinaryFractionClassical(q : Qubit, j : Bool[]) : Unit is Adj + Ctl {
+        let n = Length(j);
+        let jIntBE = BoolArrayAsInt(Reversed(j));
+        R1(2.0 * PI() * IntAsDouble(jIntBE) / IntAsDouble(1 <<< n), q);
+    }
+}
\ No newline at end of file
diff --git a/katas/content/qft/binary_fraction_classical/Verification.qs b/katas/content/qft/binary_fraction_classical/Verification.qs
new file mode 100644
index 00000000..3b2cc2b9
--- /dev/null
+++ b/katas/content/qft/binary_fraction_classical/Verification.qs
@@ -0,0 +1,32 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Arrays;
+    open Microsoft.Quantum.Convert;
+    open Microsoft.Quantum.Katas;
+    open Microsoft.Quantum.Math;
+
+    operation BinaryFractionClassical_Alternative (q : Qubit, j : Bool[]) : Unit is Adj+Ctl {
+        // Convert the number to an integer and apply a single R1 rotation
+        R1(2.0 * PI() * IntAsDouble(BoolArrayAsInt(Reversed(j))) / IntAsDouble(1 <<< Length(j)), q);
+    }
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        for n in 1 .. 5 {
+            for exp in 0 .. (1 <<< n) - 1 {
+                let j = Reversed(IntAsBoolArray(exp, n));
+                let solution = qs => Kata.BinaryFractionClassical(qs[0], j);
+                let reference = qs => BinaryFractionClassical_Alternative(qs[0], j);
+                if not CheckOperationsAreEqualStrict(1, solution, reference) {
+                    Message($"Incorrect for j = {j}.");
+                    Message("Hint: examine the effect your solution has on the state 0.6|0〉 + 0.8|1〉 and compare it with the effect it " +
+                        "is expected to have.");
+                    ShowQuantumStateComparison(1, qs => Ry(ArcTan2(0.8, 0.6) * 2.0, qs[0]), solution, reference);
+                    return false;
+                }
+            }
+        }
+
+        Message("Correct!");
+        true
+    }
+}
diff --git a/katas/content/qft/binary_fraction_classical/index.md b/katas/content/qft/binary_fraction_classical/index.md
new file mode 100644
index 00000000..a3d57fdd
--- /dev/null
+++ b/katas/content/qft/binary_fraction_classical/index.md
@@ -0,0 +1,9 @@
+**Inputs**:
+
+1. A qubit in state $\ket{\psi} = \alpha \ket{0} + \beta \ket{1}$.
+2. An array of $n$ bits $[j_1, j_2, ..., j_n]$, stored as `Bool[]`.
+
+**Goal**: 
+Change the state of the qubit to $\alpha \ket{0} + \beta \cdot e^{2\pi i \cdot 0.j_1 j_2 ... j_n} \ket{1}$, where $0.j_1 j_2 ... j_n$ is a binary fraction in big endian notation, similar to decimal fractions:
+
+$$0.j_1 j_2 ... j_n = j_1 \cdot \frac{1}{2^1} + j_2 \cdot \frac{1}{2^2} + ... + j_n \cdot \frac{1}{2^n}$$
diff --git a/katas/content/qft/binary_fraction_classical/solution.md b/katas/content/qft/binary_fraction_classical/solution.md
new file mode 100644
index 00000000..6d4ffd83
--- /dev/null
+++ b/katas/content/qft/binary_fraction_classical/solution.md
@@ -0,0 +1,56 @@
+Since you can express the exponent of a sum as a product of exponents ($e^{a+b} = e^a \cdot e^b$), you can implement the required transformation as a sequence of rotation gates from the previous task with increasing $k$.
+
+Each of the individual rotations will use the bit $j_k$ to decide whether to apply the rotation (you only want to apply the rotation if $j_k$ is true), and the index of that bit $k$ to define the rotation angle.
+The gate applied for each $k$ will be:
+
+$$U_k = \begin{cases}
+I, j_k=0 \\
+\textrm{R1Frac}(2, k), j_k=1
+\end{cases}$$
+
+Recall that 
+
+$$ \textrm{R1Frac}(2, k)( \alpha \ket{0} + \beta \ket{1}) = \alpha \ket{0} + \beta \cdot e^{2\pi i/2^{k}} \ket{1} = \alpha \ket{0} + \beta \cdot e^{2\pi i \cdot 0. \underset{k-1}{\underbrace{0\dots0}} 1} \ket{1}$$
+
+This means that the overall effect of the gate $U_k$ for each $k$ is:
+
+$$U_k (\alpha \ket{0} + \beta \ket{1}) = \alpha \ket{0} + \beta \cdot e^{2\pi i \cdot 0. \underset{k-1}{\underbrace{0\dots0}} j_k} \ket{1}$$
+
+As you iterate over $k$, the resulting state will get closer and closer to the required one:
+
+<table>
+    <tr>
+        <th>$k$</th>
+        <th>State after step $k$</th>
+    </tr>
+    <tr>
+        <td>$1$</td>
+        <td>$$\alpha \ket{0} + \beta \cdot e^{2\pi i \cdot 0.j_1} \ket{1}$$</td>
+    </tr>
+    <tr>
+        <td>$2$</td>
+        <td>$$\alpha \ket{0} + \beta \cdot e^{2\pi i \cdot 0.j_1j_2} \ket{1}$$</td>
+    </tr>
+    <tr>
+        <td>...</td>
+        <td>...</td>
+    </tr>
+    <tr>
+        <td>$n$</td>
+        <td>$$\alpha \ket{0} + \beta \cdot e^{2\pi i \cdot 0.j_1j_2 \dots j_n}\ket{1}$$</td>
+    </tr>
+</table>
+
+@[solution]({
+"id": "qft__binary_fraction_classical_solution_a",
+"codePath": "./SolutionA.qs"
+})
+
+Alternatively, you can do this in a single rotation using the $R1$ gate if you convert the array $j$ into a rotation angle. You'll need the angle $2\pi \cdot 0.j_1j_2 \dots j_n$, and this fraction can be calculated by converting the bit string into an integer $j$ (using big endian notation) and dividing it by $2^n$.
+
+This solution is better when considered on its own, since it involves doing only a single rotation rather than a series of them. However, it will not be as helpful as the first one once you get to the next task!
+
+@[solution]({
+"id": "qft__binary_fraction_classical_solution_b",
+"codePath": "./SolutionB.qs"
+})
diff --git a/katas/content/qft/binary_fraction_inplace/Placeholder.qs b/katas/content/qft/binary_fraction_inplace/Placeholder.qs
new file mode 100644
index 00000000..b4ab86ea
--- /dev/null
+++ b/katas/content/qft/binary_fraction_inplace/Placeholder.qs
@@ -0,0 +1,6 @@
+namespace Kata {
+    operation BinaryFractionQuantumInPlace(j : Qubit[]) : Unit is Adj + Ctl {
+        // Implement your solution here...
+     
+    }
+}
diff --git a/katas/content/qft/binary_fraction_inplace/Solution.qs b/katas/content/qft/binary_fraction_inplace/Solution.qs
new file mode 100644
index 00000000..9102ce5b
--- /dev/null
+++ b/katas/content/qft/binary_fraction_inplace/Solution.qs
@@ -0,0 +1,8 @@
+namespace Kata {
+    operation BinaryFractionQuantumInPlace(j : Qubit[]) : Unit is Adj + Ctl {
+        H(j[0]);
+        for ind in 1 .. Length(j) - 1 {
+            Controlled R1Frac([j[ind]], (2, ind + 1, j[0]));
+        }
+    }
+}
\ No newline at end of file
diff --git a/katas/content/qft/binary_fraction_inplace/Verification.qs b/katas/content/qft/binary_fraction_inplace/Verification.qs
new file mode 100644
index 00000000..e20e9bb0
--- /dev/null
+++ b/katas/content/qft/binary_fraction_inplace/Verification.qs
@@ -0,0 +1,26 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Arrays;
+    open Microsoft.Quantum.Convert;
+    open Microsoft.Quantum.Katas;
+    open Microsoft.Quantum.Math;
+
+    operation BinaryFractionQuantumInPlace_Reference(j : Qubit[]) : Unit is Adj + Ctl {
+        H(j[0]);
+        for ind in 1 .. Length(j) - 1 {
+            Controlled R1Frac([j[ind]], (2, ind + 1, j[0]));
+        }
+    }
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        for n in 1 .. 5 {
+            if not CheckOperationsAreEqualStrict(n, Kata.BinaryFractionQuantumInPlace, BinaryFractionQuantumInPlace_Reference) {
+                Message($"Incorrect for n = {n}.");
+                return false;
+            }
+        }
+
+        Message("Correct!");
+        true
+    }
+}
diff --git a/katas/content/qft/binary_fraction_inplace/index.md b/katas/content/qft/binary_fraction_inplace/index.md
new file mode 100644
index 00000000..71e15cf7
--- /dev/null
+++ b/katas/content/qft/binary_fraction_inplace/index.md
@@ -0,0 +1,11 @@
+**Input**:
+A register of $n$ qubits in state $\ket{j_1 j_2 ... j_n}$.
+
+**Goal**: 
+Change the state of the register from $\ket{j_1} \otimes \ket{j_2 ... j_n}$ to $\frac1{\sqrt2}(\ket{0} + e^{2\pi i \cdot 0.j_1 j_2 ... j_n} \ket{1}) \otimes \ket{j_2 ... j_n}$.
+
+<details>
+  <summary><b>Need a hint?</b></summary>
+  
+This task is very similar to the previous task, but the digit $j_1$ has to be encoded in-place. You can do this using the first task of the kata, "Single-Qubit QFT".
+</details>
diff --git a/katas/content/qft/binary_fraction_inplace/solution.md b/katas/content/qft/binary_fraction_inplace/solution.md
new file mode 100644
index 00000000..614bcc57
--- /dev/null
+++ b/katas/content/qft/binary_fraction_inplace/solution.md
@@ -0,0 +1,14 @@
+First, let's recall the first task of the kata: a Hadamard gate applied to a single qubit,  $H\ket{j_1}$, will give either
+$\frac1{\sqrt2}(\ket{0} + \ket{1})$ or $\frac{1}{\sqrt{2}}(\ket{0} - \ket{1})$ depending on the state of $\ket{j_1}$. This operation can also be written as
+$$H\ket{j_1} = \frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot \frac{j_1}{2}}\ket{1} \big)= \frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot 0.j_1}\ket{1} \big)$$
+
+So, if the starting register state is $\ket{j_1 j_2 ... j_n}$, applying a Hadamard gate to the first qubit will result in:
+
+$$\big(H_1\otimes I_{n-1} \big) \big(\ket{j_1} \otimes \ket{j_2 ... j_n} \big)= \frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot 0.j_1}\ket{1} \big) \otimes \ket{j_2 ... j_n} $$
+
+After this, we can repeat the loop we used in the previous task for qubits $\ket{j_2 ... j_n}$ with the first qubit as the target to adjust the remaining phase terms via the controlled $\textrm{R1Frac}$ gate.
+
+@[solution]({
+"id": "qft__binary_fraction_inplace_solution",
+"codePath": "./Solution.qs"
+})
diff --git a/katas/content/qft/binary_fraction_quantum/Placeholder.qs b/katas/content/qft/binary_fraction_quantum/Placeholder.qs
new file mode 100644
index 00000000..ff92f1e1
--- /dev/null
+++ b/katas/content/qft/binary_fraction_quantum/Placeholder.qs
@@ -0,0 +1,6 @@
+namespace Kata {
+    operation BinaryFractionQuantum(q : Qubit, j : Qubit[]) : Unit is Adj + Ctl {
+        // Implement your solution here...
+     
+    }
+}
diff --git a/katas/content/qft/binary_fraction_quantum/Solution.qs b/katas/content/qft/binary_fraction_quantum/Solution.qs
new file mode 100644
index 00000000..8b3c5d44
--- /dev/null
+++ b/katas/content/qft/binary_fraction_quantum/Solution.qs
@@ -0,0 +1,7 @@
+namespace Kata {
+    operation BinaryFractionQuantum(q : Qubit, j : Qubit[]) : Unit is Adj + Ctl {
+        for ind in 0 .. Length(j) - 1 {
+            Controlled R1Frac([j[ind]], (2, ind + 1, q));
+        }
+    }
+}
\ No newline at end of file
diff --git a/katas/content/qft/binary_fraction_quantum/Verification.qs b/katas/content/qft/binary_fraction_quantum/Verification.qs
new file mode 100644
index 00000000..58631977
--- /dev/null
+++ b/katas/content/qft/binary_fraction_quantum/Verification.qs
@@ -0,0 +1,27 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Arrays;
+    open Microsoft.Quantum.Convert;
+    open Microsoft.Quantum.Katas;
+    open Microsoft.Quantum.Math;
+
+    operation BinaryFractionQuantum_Reference(q : Qubit, j : Qubit[]) : Unit is Adj + Ctl {
+        for ind in 0 .. Length(j) - 1 {
+            Controlled R1Frac([j[ind]], (2, ind + 1, q));
+        }
+    }
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        for n in 1 .. 5 {
+            let solution = qs => Kata.BinaryFractionQuantum(qs[0], qs[1 ...]);
+            let reference = qs => BinaryFractionQuantum_Reference(qs[0], qs[1 ...]);
+            if not CheckOperationsAreEqualStrict(n + 1, solution, reference) {
+                Message($"Incorrect for n = {n}.");
+                return false;
+            }
+        }
+
+        Message("Correct!");
+        true
+    }
+}
diff --git a/katas/content/qft/binary_fraction_quantum/index.md b/katas/content/qft/binary_fraction_quantum/index.md
new file mode 100644
index 00000000..6e11d50c
--- /dev/null
+++ b/katas/content/qft/binary_fraction_quantum/index.md
@@ -0,0 +1,10 @@
+**Inputs**:
+
+1. A qubit in state $\ket{\psi} = \alpha \ket{0} + \beta \ket{1}$.
+2. An array of $n$ qubits $j$ in state $\ket{j_1 j_2 ... j_n}$.
+
+**Goal**: 
+Change the state of the input qubits from $(\alpha \ket{0} + \beta \ket{1}) \otimes \ket{j_1 j_2 ... j_n}$ to $(\alpha \ket{0} + \beta \cdot e^{2\pi i \cdot 0.j_1 j_2 ... j_n} \ket{1}) \otimes \ket{j_1 j_2 ... j_n}$, where $0.j_1 j_2 ... j_n$ is a binary fraction corresponding to the basis state $j_1 j_2 ... j_n$ of the qubit array $j$.
+
+> The qubit array can be in superposition as well;
+the behavior of the transformation in this case is defined by its behavior on the basis states and the linearity of unitary transformations.
diff --git a/katas/content/qft/binary_fraction_quantum/solution.md b/katas/content/qft/binary_fraction_quantum/solution.md
new file mode 100644
index 00000000..53926654
--- /dev/null
+++ b/katas/content/qft/binary_fraction_quantum/solution.md
@@ -0,0 +1,8 @@
+From the goal of the exercise, you can see that the register $j$ has to remain unchanged, while the first input qubit should acquire a phase that depends on the value of the qubits in the register $j$.
+
+Since $j$ is a quantum register and can be in a superposition of basis states, you cannot just measure the register and then apply the operation from the previous task using measurement results as the second argument. Instead, you have to convert the solution to the previous task from using $\textrm{R1Frac}$ gates with classical conditions to using them as controlled operations, with the qubits of the register $j$ as quantum conditions. You can do this using the `Controlled` functor.
+
+@[solution]({
+"id": "qft__binary_fraction_quantum_solution",
+"codePath": "./Solution.qs"
+})
diff --git a/katas/content/qft/index.md b/katas/content/qft/index.md
new file mode 100644
index 00000000..df6403a8
--- /dev/null
+++ b/katas/content/qft/index.md
@@ -0,0 +1,183 @@
+# Quantum Fourier Transform
+
+@[section]({
+    "id": "qft__overview",
+    "title": "Overview"
+})
+
+This kata introduces you to quantum Fourier transform (QFT) - an important tool in quantum phase estimation, integer factoring, and many other quantum computing algorithms.
+
+**This kata covers the following topics:**
+
+- The definition of quantum Fourier transform
+- The iterative implementation of QFT
+- Simple state preparation and state analysis tasks that can be solved using QFT
+
+**What you should know to start working on this kata:**
+
+- Basic knowledge of quantum states and quantum gates.
+
+If you need a refresher on these topics, you can check out the previous katas.
+
+
+@[section]({
+    "id": "qft__implement",
+    "title": "Implementing Quantum Fourier Transform"
+})
+
+*Discrete Fourier transform* (DFT) is a transform that acts on vectors of complex numbers of fixed length $N$. The effect of DFT on a vector $x_0, x_1, ..., x_{N-1}$ is another vector $y_0, y_1, ..., y_{N-1}$ defined as follows:
+
+$$y_k = \frac1{\sqrt{N}}\sum_{j=0}^{N-1} x_j e^{2\pi i jk/N}$$
+
+Quantum Fourier transform is the quantum version of the DFT. It acts on $n$-qubit quantum states and is defined via its effects on basis states as follows:
+
+$$\ket{j} \rightarrow \frac1{\sqrt{2^n}}\sum_{k=0}^{2^n-1}  e^{2\pi i jk/2^n} \ket{k}$$
+
+The result of applying QFT to an arbitrary superposition state with amplitudes $x_j$ can thus be expressed as a superposition state with amplitudes $y_k$ that are exactly the DFT of the amplitudes $x_j$ for $N = 2^n$:
+
+$$\sum_{j=0}^{N-1} x_j\ket{j} \rightarrow \sum_{k=0}^{N-1} y_k\ket{k}$$
+
+In the first part of this kata, you will learn to implement quantum Fourier transform using the iterative algorithm.
+
+All the numbers used in this kata use big endian encoding: the most significant bit of the number is stored in the first (leftmost) bit/qubit.
+ 
+This means that you represent an integer as a binary bit string in the following format:
+
+$$x = x_1x_2...x_n = x_1 2^{n-1} + x_2 2^{n-2}+...x_n 2^{0}$$
+ 
+You can also use this notation for binary fractions: 
+ 
+$$0.x_1x_2...x_n = \frac{x_1}{2^1}+ \frac{x_2}{2^2}+...\frac{x_n}{2^n}$$
+ 
+@[exercise]({
+    "id": "qft__single_qubit",
+    "title": "Single-Qubit QFT",
+    "path": "./single_qubit/"
+})
+
+@[exercise]({
+    "id": "qft__rotation_gate",
+    "title": "Rotation Gate",
+    "path": "./rotation_gate/"
+})
+
+@[exercise]({
+    "id": "qft__binary_fraction_classical",
+    "title": "Binary Fraction Exponent (Classical Input)",
+    "path": "./binary_fraction_classical/"
+})
+
+@[exercise]({
+    "id": "qft__binary_fraction_quantum",
+    "title": "Binary Fraction Exponent (Quantum Input)",
+    "path": "./binary_fraction_quantum/"
+})
+
+@[exercise]({
+    "id": "qft__binary_fraction_inplace",
+    "title": "Binary Fraction Exponent In-Place (Quantum Input)",
+    "path": "./binary_fraction_inplace/"
+})
+
+@[exercise]({
+    "id": "qft__qft",
+    "title": "Quantum Fourier Transform",
+    "path": "./qft/"
+})
+
+
+@[section]({
+    "id": "qft__equivalence",
+    "title": "The Equivalence of Two QFT Notations"
+})
+
+How to show that the transformation defined in the last exercise is the same as the original definition of QFT?
+In other words, how to prove the equality below?
+
+$$\frac1{\sqrt{2^n}} \sum_{k=0}^{2^n-1} e^{2\pi i \cdot \frac{jk}{2^{n}}} \ket{k} = $$
+$$\begin{align*}
+= &\frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot 0.j_n} \ket{1} \big) \otimes \\
+\otimes &\frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot 0.j_{n-1} j_n} \ket{1} \big) \otimes ... \otimes \\
+\otimes &\frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot 0.j_1 j_2 ... j_{n-1} j_n} \ket{1} \big)
+\end{align*}$$
+ 
+The tensor product state is defined in terms of the digits $j_1, j_2, ..., j_n$. Let's spell the exponents used in each term of the tensor product in terms of the integer $j$ instead:
+$$e^{2\pi i \cdot 0.j_1 j_2 ... j_{n-1} j_n} = e^{2\pi i \cdot \frac{j}{2^n}}$$
+$$e^{2\pi i \cdot 0.j_2 ... j_{n-1} j_n} = e^{2\pi i \cdot j_1} e^{2\pi i \cdot 0.j_2 ... j_{n-1} j_n} = e^{2\pi i \cdot j_1.j_2 ... j_{n-1} j_n} = e^{2\pi i \cdot \frac{j \cdot 2}{2^n}}$$
+(Remember that since $j_1$ can only be $0$ or $1$, $e^{2\pi i \cdot j_1}$ is either $e^0$ or $e^{2\pi i}$, which are both $1$. Any exponents of integer multiples of $e^{2\pi i}$ are $1$ and thus can be ignored.)
+
+And so on, until the last term:
+$$e^{2\pi i \cdot 0.j_n} = e^{2\pi i \cdot \frac{j \cdot 2^{n-1}}{2^n}}$$
+
+Now, the complete state looks as follows:
+$$\begin{align*}
+&\frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot \frac{j \cdot 2^{n-1}}{2^n}} \ket{1} \big) \otimes \\
+\otimes &\frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot \frac{j \cdot 2^{n-2}}{2^n}} \ket{1} \big) \otimes ... \otimes \\
+\otimes &\frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot \frac{j}{2^n}} \ket{1} \big)
+\end{align*}$$
+
+What happens if you open the brackets and compare the results to the definition of the QFT?
+Let's do this exercise for $n = 2$.
+
+$$\frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot \frac{j \cdot 2}{4}} \ket{1} \big) \otimes \frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot \frac{j}{4}} \ket{1} \big) = $$
+$$= \frac14 \big( \ket{00} + e^{2\pi i \cdot \frac{j}{4}}\ket{01} + e^{2\pi i \cdot \frac{j \cdot 2}{4}}\ket{10} + e^{2\pi i \cdot \frac{j \cdot 2 + j}{4}} \ket{11} \big)$$
+
+Remember that this kata uses big endian to map bit strings to integers, so this can be rewritten as follows:
+$$\frac14 \big( \ket{0} + e^{2\pi i \cdot \frac{j}{4}}\ket{1} + e^{2\pi i \cdot \frac{j \cdot 2}{4}}\ket{2} + e^{2\pi i \cdot \frac{j \cdot 3}{4}} \ket{3} \big)$$
+And that's exactly the original definition of QFT:
+$$\frac1{\sqrt{4}}\sum_{k=0}^{3}  e^{2\pi i jk/4} \ket{k}$$
+
+The same can be done for an arbitrary $n$.
+
+
+@[section]({
+    "id": "qft__use",
+    "title": "Using Quantum Fourier Transform"
+})
+
+This section offers you tasks on state preparation and state analysis that can be solved using QFT or inverse QFT. 
+You can solve them without QFT, but it is useful to try and come up with a QFT-based solution as an exercise.
+
+@[exercise]({
+    "id": "qft__all_basis_vectors",
+    "title": "Prepare Even Superposition of All Basis Vectors",
+    "path": "./all_basis_vectors/"
+})
+
+@[exercise]({
+    "id": "qft__periodic_state",
+    "title": "Prepare a Periodic State",
+    "path": "./periodic_state/"
+})
+
+@[exercise]({
+    "id": "qft__alternating_amplitudes",
+    "title": "Prepare a State with Alternating Amplitudes",
+    "path": "./alternating_amplitudes/"
+})
+
+@[exercise]({
+    "id": "qft__all_even_vectors",
+    "title": "Prepare Even Superposition of All Even Basis Vectors",
+    "path": "./all_even_vectors/"
+})
+
+@[exercise]({
+    "id": "qft__square_wave",
+    "title": "Prepare Square-Wave Signal",
+    "path": "./square_wave/"
+})
+
+@[exercise]({
+    "id": "qft__signal_frequency",
+    "title": "Get Signal Frequency",
+    "path": "./signal_frequency/"
+})
+
+
+@[section]({
+    "id": "qft__conclusion",
+    "title": "Conclusion"
+})
+
+Congratulations! In this kata you learned to implement the quantum Fourier transform and to use it in simple tasks. In the next kata, you will learn to use the QFT to solve a more complicated problem - the phase estimation task.
diff --git a/katas/content/qft/periodic_state/Placeholder.qs b/katas/content/qft/periodic_state/Placeholder.qs
new file mode 100644
index 00000000..9d136b95
--- /dev/null
+++ b/katas/content/qft/periodic_state/Placeholder.qs
@@ -0,0 +1,14 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+
+    operation PeriodicState(qs : Qubit[], F : Int) : Unit is Adj + Ctl {
+        // Implement your solution here...
+
+    }
+
+    // You might find this helper operation that implements QFT using a library operation useful.
+    operation QFT(qs : Qubit[]) : Unit is Adj + Ctl {
+        ApplyQFT(Reversed(qs));
+        SwapReverseRegister(qs);
+    }
+}
diff --git a/katas/content/qft/periodic_state/Solution.qs b/katas/content/qft/periodic_state/Solution.qs
new file mode 100644
index 00000000..a6fe1b0a
--- /dev/null
+++ b/katas/content/qft/periodic_state/Solution.qs
@@ -0,0 +1,15 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+    open Microsoft.Quantum.Convert;
+
+    operation PeriodicState(qs : Qubit[], F : Int) : Unit is Adj + Ctl {
+        let bitsBE = Reversed(IntAsBoolArray(F, Length(qs)));
+        ApplyPauliFromBitString(PauliX, true, bitsBE, qs);
+        QFT(qs);
+    }
+
+    operation QFT(qs : Qubit[]) : Unit is Adj + Ctl {
+        ApplyQFT(Reversed(qs));
+        SwapReverseRegister(qs);
+    }
+}
diff --git a/katas/content/qft/periodic_state/Verification.qs b/katas/content/qft/periodic_state/Verification.qs
new file mode 100644
index 00000000..b1df526b
--- /dev/null
+++ b/katas/content/qft/periodic_state/Verification.qs
@@ -0,0 +1,33 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Arrays;
+    open Microsoft.Quantum.Convert;
+    open Microsoft.Quantum.Katas;
+    open Microsoft.Quantum.Math;
+    open Microsoft.Quantum.Unstable.StatePreparation;
+
+    operation PeriodicState_Reference (qs : Qubit[], F : Int) : Unit is Adj + Ctl {
+        let n = Length(qs);
+        let amps = MappedOverRange(
+            k -> ComplexPolar(1.0, 2. * PI() * IntAsDouble(F * k) / IntAsDouble(2 ^ n)), 
+            0 .. 2 ^ n - 1);
+        ApproximatelyPreparePureStateCP(0.0, amps, qs);
+    }
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        for n in 1 .. 3 {
+            for F in 0 .. 2 ^ n - 1 {
+                let solution = Kata.PeriodicState(_, F);
+                let reference = PeriodicState_Reference(_, F);
+                if not CheckOperationsEquivalenceOnZeroState(solution, reference, n) {
+                    Message($"Incorrect for {n} qubit(s), F = {F}");
+                    ShowQuantumStateComparison(n, qs => (), solution, reference);
+                    return false;
+                }
+            }
+        }
+
+        Message("Correct!");
+        return true;
+    }
+}
diff --git a/katas/content/qft/periodic_state/index.md b/katas/content/qft/periodic_state/index.md
new file mode 100644
index 00000000..16e26ef6
--- /dev/null
+++ b/katas/content/qft/periodic_state/index.md
@@ -0,0 +1,10 @@
+**Inputs:**
+
+1. $n$ qubits in the $\ket{0 \dots 0}$ state.
+2. An integer frequency $F$ ($0 \leq F \leq 2^{n}-1$).
+
+**Goal:**  Change the state of the qubits to a periodic state with frequency $F$:
+
+$$\frac1{\sqrt{2^n}} \sum_{k=0}^{2^n-1} e^{2\pi i \cdot \frac{Fk}{2^{n}}} \ket{k}$$
+
+> For example, for $n = 2$ and $F = 1$ the goal state is $\frac12\big(\ket{0} + i\ket{1} - \ket{2} - i\ket{3} \big)$.
diff --git a/katas/content/qft/periodic_state/solution.md b/katas/content/qft/periodic_state/solution.md
new file mode 100644
index 00000000..9c27880b
--- /dev/null
+++ b/katas/content/qft/periodic_state/solution.md
@@ -0,0 +1,15 @@
+Recall the definition of the QFT: 
+for a basis state $\ket{j}$, the QFT is defined as 
+
+$$QFT\ket{j}= \frac1{\sqrt{2^n}} \sum_{k=0}^{2^n-1} e^{2\pi i \cdot j k/2^{n}} \ket{k}$$
+
+You can see that using $j = F$ will produce exactly the required state!
+
+To prepare the state $\ket{F}$ on the input register, you need to convert the integer value $F$ into a big endian binary representation and encode it in the register. 
+
+> When writing the code, make sure that you pay attention to whether library functions use little or big endian!  In particular, `IntAsBoolArray` uses little endian encoding, and the QFT operation uses big endian, so the result of converting the integer into a bit string must be reversed before encoding it in the register. 
+
+@[solution]({
+    "id": "qft__periodic_state_solution",
+    "codePath": "./Solution.qs"
+})
diff --git a/katas/content/qft/qft/Placeholder.qs b/katas/content/qft/qft/Placeholder.qs
new file mode 100644
index 00000000..d2db8f75
--- /dev/null
+++ b/katas/content/qft/qft/Placeholder.qs
@@ -0,0 +1,14 @@
+namespace Kata {
+    operation QuantumFourierTransform(j : Qubit[]) : Unit is Adj + Ctl {
+        // Implement your solution here...
+     
+    }
+
+    // You might find this helper operation from an earlier task useful.
+    operation BinaryFractionQuantumInPlace(j : Qubit[]) : Unit is Adj + Ctl {
+        H(j[0]);
+        for ind in 1 .. Length(j) - 1 {
+            Controlled R1Frac([j[ind]], (2, ind + 1, j[0]));
+        }
+    }
+}
diff --git a/katas/content/qft/qft/Solution.qs b/katas/content/qft/qft/Solution.qs
new file mode 100644
index 00000000..0375cf45
--- /dev/null
+++ b/katas/content/qft/qft/Solution.qs
@@ -0,0 +1,18 @@
+namespace Kata {
+    operation QuantumFourierTransform(j : Qubit[]) : Unit is Adj + Ctl {
+        let n = Length(j);
+        for ind in 0 .. n - 1 {
+            BinaryFractionQuantumInPlace(j[ind ...]);
+        }
+        for ind in 0 .. n / 2 - 1 {
+            SWAP(j[ind], j[n - 1 - ind]);
+        }        
+    }
+
+    operation BinaryFractionQuantumInPlace(j : Qubit[]) : Unit is Adj + Ctl {
+        H(j[0]);
+        for ind in 1 .. Length(j) - 1 {
+            Controlled R1Frac([j[ind]], (2, ind + 1, j[0]));
+        }
+    }
+}
\ No newline at end of file
diff --git a/katas/content/qft/qft/Verification.qs b/katas/content/qft/qft/Verification.qs
new file mode 100644
index 00000000..10541c3e
--- /dev/null
+++ b/katas/content/qft/qft/Verification.qs
@@ -0,0 +1,22 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Arrays;
+    open Microsoft.Quantum.Katas;
+    
+    operation LibraryQFT(qs : Qubit[]) : Unit is Adj + Ctl {
+        ApplyQFT(Reversed(qs));
+        SwapReverseRegister(qs);
+    }
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        for n in 1 .. 5 {
+            if not CheckOperationsAreEqualStrict(n, Kata.QuantumFourierTransform, LibraryQFT) {
+                Message($"Incorrect for n = {n}.");
+                return false;
+            }
+        }
+
+        Message("Correct!");
+        true
+    }
+}
diff --git a/katas/content/qft/qft/index.md b/katas/content/qft/qft/index.md
new file mode 100644
index 00000000..2a7436e7
--- /dev/null
+++ b/katas/content/qft/qft/index.md
@@ -0,0 +1,22 @@
+**Input**:
+A register of $n$ qubits in state $\ket{j_1 j_2 ... j_n}$.
+
+**Goal**: 
+Apply quantum Fourier transform to the input register, that is, transform it to a state
+
+$$\begin{align*}
+&\frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot 0.j_n} \ket{1} \big) \otimes \\
+\otimes &\frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot 0.j_{n-1} j_n} \ket{1} \big) \otimes ... \otimes \\
+\otimes &\frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot 0.j_1 j_2 ... j_{n-1} j_n} \ket{1} \big)
+\end{align*}$$
+
+The register of qubits can be in superposition as well;
+the behavior in this case is defined by behavior on the basis states and the linearity of unitary transformations.
+
+> Notice that this implementation will let you use inverse QFT without writing any extra code, just by using the adjoint of this operation!
+
+<details>
+  <summary><b>Need a hint?</b></summary>
+  
+Consider first preparing a state with the states of individual qubits reversed and then transforming it to the goal state.
+</details>
\ No newline at end of file
diff --git a/katas/content/qft/qft/solution.md b/katas/content/qft/qft/solution.md
new file mode 100644
index 00000000..6212f988
--- /dev/null
+++ b/katas/content/qft/qft/solution.md
@@ -0,0 +1,33 @@
+Let's use the hint and start by preparing the described state with the qubits reversed:
+
+$$\begin{align*}
+&\frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot 0.j_1 j_2 ... j_{n-1} j_n} \ket{1} \big) \otimes \\
+&\frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot 0.j_2 ... j_{n-1} j_n} \ket{1} \big) \otimes ... \otimes \\
+\otimes &\frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot 0.j_{n-1} j_n} \ket{1} \big) \otimes \\
+\otimes &\frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot 0.j_n} \ket{1} \big)
+\end{align*}$$
+
+You've already found a way to prepare a binary fraction exponent (the desired state of the first qubit) in-place in the previous task. The state $\frac1{\sqrt2} \big(\ket{0} + e^{2\pi i \cdot 0.j_1 j_2 ... j_{n-1} j_n} \ket{1} \big) \otimes \ket{j_2 ... j_n}$ can be prepared by first applying the Hadamard gate to the first qubit in state $\ket{j_1}$ and then applying a succession of controlled rotations using qubits $\ket{j_k}$ with increasing values of $k$ as controls, so that an extra phase terms from $e^{2\pi i \cdot j_2/2^2}$ all the way up to $e^{2\pi i \cdot j_n/2^{n}}$ are added with each rotation. 
+
+This will prepare the first qubit in the right state. You can see that $j_1$ doesn't appear in the rest of the expression for the target state, so you won't need to use it in the rest of the code.
+
+To prepare the remaining qubits in the right states, you can work backwards from this state.
+The second qubit in the sequence needs to be prepared in the state $\frac{1}{\sqrt{2}} \big(\ket{0} + e^{2\pi i \cdot 0.j_2 ... j_{n-1} j_n} \ket{1} \big)$. 
+Similarly to the first qubit, you can do this by applying a Hadamard gate to the qubit $\ket{j_2}$ and then using qubits $\ket{j_3}$ to $\ket{j_n}$ to apply $n-2$ controlled rotation gates to the second qubit. 
+After this operation, the total system state will be: 
+
+$$\frac{1}{\sqrt{2}} \big(\ket{0} + e^{2\pi i \cdot 0.j_1 j_2 ... j_{n-1} j_n} \ket{1} \big)\otimes
+\frac{1}{\sqrt{2}} \big(\ket{0} + e^{2\pi i \cdot 0.j_2 ... j_{n-1} j_n} \ket{1} \big) \otimes \ket{j_3 ... j_n}$$
+
+These two steps allow us to see a pattern: for each qubit $j_k, k = 1 .. n$ :
+
+1. Apply a Hadamard gate to $|j_k\rangle$.
+2. Apply the controlled rotation operator $n-k$ times to the qubit $|j_k\rangle$, using qubits $|j_{k+1}\rangle$ through $|j_n\rangle$ as the controls, with phases corresponding to fractions from $2^2$ to $2^{n-k+1}$.
+
+The effect of these steps will be preparing the state that almost matches the required state, but has the qubit order reversed compared to it. 
+You can fix that by using a series of $\textrm{SWAP}$ gates to reverse the order of qubits in the state.
+
+@[solution]({
+"id": "qft__qft_solution",
+"codePath": "./Solution.qs"
+})
diff --git a/katas/content/qft/rotation_gate/Placeholder.qs b/katas/content/qft/rotation_gate/Placeholder.qs
new file mode 100644
index 00000000..dac1dc5e
--- /dev/null
+++ b/katas/content/qft/rotation_gate/Placeholder.qs
@@ -0,0 +1,6 @@
+namespace Kata {
+    operation Rotation(q : Qubit, k : Int) : Unit is Adj + Ctl {
+        // Implement your solution here...
+     
+    }
+}
diff --git a/katas/content/qft/rotation_gate/Solution.qs b/katas/content/qft/rotation_gate/Solution.qs
new file mode 100644
index 00000000..59d805f0
--- /dev/null
+++ b/katas/content/qft/rotation_gate/Solution.qs
@@ -0,0 +1,5 @@
+namespace Kata {
+    operation Rotation(q : Qubit, k : Int) : Unit is Adj + Ctl {
+        R1Frac(2, k, q);
+    }
+}
\ No newline at end of file
diff --git a/katas/content/qft/rotation_gate/Verification.qs b/katas/content/qft/rotation_gate/Verification.qs
new file mode 100644
index 00000000..267e5b0a
--- /dev/null
+++ b/katas/content/qft/rotation_gate/Verification.qs
@@ -0,0 +1,22 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Katas;
+    open Microsoft.Quantum.Math;
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        for k in 0 .. 10 {
+            let solution = qs => Kata.Rotation(qs[0], k);
+            let reference = qs => R1Frac(2, k, qs[0]);
+            if not CheckOperationsAreEqualStrict(1, solution, reference) {
+                Message($"Incorrect for k = {k}.");
+                Message("Hint: examine the effect your solution has on the state 0.6|0〉 + 0.8|1〉 and compare it with the effect it " +
+                    "is expected to have.");
+                ShowQuantumStateComparison(1, qs => Ry(ArcTan2(0.8, 0.6) * 2.0, qs[0]), solution, reference);
+                return false;
+            }
+        }
+
+        Message("Correct!");
+        true
+    }
+}
diff --git a/katas/content/qft/rotation_gate/index.md b/katas/content/qft/rotation_gate/index.md
new file mode 100644
index 00000000..b647e00d
--- /dev/null
+++ b/katas/content/qft/rotation_gate/index.md
@@ -0,0 +1,10 @@
+**Inputs**:
+
+1. A qubit in state $\ket{\psi} = \alpha \ket{0} + \beta \ket{1}$.
+2. An integer $k \geq 0$.
+
+**Goal**: 
+Change the state of the qubit to $\alpha \ket{0} + \beta \cdot e^{\frac{2\pi i}{2^{k}}} \ket{1}$
+
+> Be careful not to introduce an extra global phase! 
+This is going to be important in the later exercises.
\ No newline at end of file
diff --git a/katas/content/qft/rotation_gate/solution.md b/katas/content/qft/rotation_gate/solution.md
new file mode 100644
index 00000000..dee5fb6d
--- /dev/null
+++ b/katas/content/qft/rotation_gate/solution.md
@@ -0,0 +1,14 @@
+To avoid adding the extra global phase, we have to use a gate that does not modify the $\ket{0}$ state, and only impacts $\ket{1}$: that is, $U\ket{\psi} = \alpha\ket{0} + \beta \cdot U\ket{1}$.
+
+The built-in [R1Frac gate](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.intrinsic/r1frac) does exactly that:
+
+$$\textrm{R1Frac}(n,k) = \begin{bmatrix} 1 & 0 \\ 0 & e^{i\pi n/2^{k}} \end{bmatrix} $$
+
+We specify $n=2$ to get the transformation required: 
+
+$$\textrm{R1Frac}(2,k) = \begin{bmatrix} 1 & 0 \\ 0 & e^{2\pi i/2^{k}} \end{bmatrix} $$
+
+@[solution]({
+"id": "qft__rotation_gate_solution",
+"codePath": "./Solution.qs"
+})
diff --git a/katas/content/qft/signal_frequency/Placeholder.qs b/katas/content/qft/signal_frequency/Placeholder.qs
new file mode 100644
index 00000000..25ffc0b9
--- /dev/null
+++ b/katas/content/qft/signal_frequency/Placeholder.qs
@@ -0,0 +1,15 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+
+    operation SignalFrequency(qs : Qubit[]) : Int {
+        // Implement your solution here...
+        
+        return -1;
+    }
+
+    // You might find this helper operation that implements QFT using a library operation useful.
+    operation QFT(qs : Qubit[]) : Unit is Adj + Ctl {
+        ApplyQFT(Reversed(qs));
+        SwapReverseRegister(qs);
+    }
+}
diff --git a/katas/content/qft/signal_frequency/Solution.qs b/katas/content/qft/signal_frequency/Solution.qs
new file mode 100644
index 00000000..d4044d07
--- /dev/null
+++ b/katas/content/qft/signal_frequency/Solution.qs
@@ -0,0 +1,13 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+
+    operation SignalFrequency(qs : Qubit[]) : Int {
+        Adjoint QFT(qs);
+        return MeasureInteger(Reversed(qs));
+    }
+
+    operation QFT(qs : Qubit[]) : Unit is Adj + Ctl {
+        ApplyQFT(Reversed(qs));
+        SwapReverseRegister(qs);
+    }
+}
diff --git a/katas/content/qft/signal_frequency/Verification.qs b/katas/content/qft/signal_frequency/Verification.qs
new file mode 100644
index 00000000..8dedb1ef
--- /dev/null
+++ b/katas/content/qft/signal_frequency/Verification.qs
@@ -0,0 +1,31 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Arrays;
+    open Microsoft.Quantum.Convert;
+    open Microsoft.Quantum.Katas;
+
+    operation PreparePeriodicState(qs : Qubit[], F : Int) : Unit is Adj + Ctl {
+        let bitsBE = Reversed(IntAsBoolArray(F, Length(qs)));
+        ApplyPauliFromBitString(PauliX, true, bitsBE, qs);
+        ApplyQFT(Reversed(qs));
+        SwapReverseRegister(qs);
+    }
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        for n in 2 .. 4 {
+            use qs = Qubit[n];
+            for F in 0 .. 2 ^ n - 1 {
+                PreparePeriodicState(qs, F);
+                let fRes = Kata.SignalFrequency(qs);
+                ResetAll(qs);
+                if fRes != F {
+                    Message($"Incorrect frequency for n = {n}, F = {F}: got {fRes}");
+                    return false;
+                }
+            }
+        }
+
+        Message("Correct!");
+        return true;
+    }
+}
diff --git a/katas/content/qft/signal_frequency/index.md b/katas/content/qft/signal_frequency/index.md
new file mode 100644
index 00000000..1793ced9
--- /dev/null
+++ b/katas/content/qft/signal_frequency/index.md
@@ -0,0 +1,10 @@
+**Input:**
+$n$ qubits in the state
+
+$$\frac1{\sqrt{2^n}} \sum_{k=0}^{2^n-1} e^{2\pi i \cdot \frac{Fk}{2^{n}}} \ket{k}$$
+
+**Output:** The frequency $F$ of the "signal" encoded in this state ($0\leq F\leq 2^n-1$).
+
+> For example, for $n = 2$ and the state $\frac12\big(\ket{0} + i\ket{1} - \ket{2} - i\ket{3} \big)$ the output should be $F = 1$.
+
+The state of the qubits at the end of the operation does not matter.
\ No newline at end of file
diff --git a/katas/content/qft/signal_frequency/solution.md b/katas/content/qft/signal_frequency/solution.md
new file mode 100644
index 00000000..8c1fa1aa
--- /dev/null
+++ b/katas/content/qft/signal_frequency/solution.md
@@ -0,0 +1,10 @@
+The classical Fourier transform produces a time-domain signal's decomposition in the frequency domain, and the inverse Fourier transform produces a frequency-domain signal's time-domain representation.
+
+Keeping this in mind, if you have the state that is the result of applying QFT to a basis state $\ket{F}$, the value $F$ can be recovered by applying the inverse QFT to this state and then measuring the qubits to find the resulting basis state.
+
+Keep in mind that QFT acts on arrays in big endian notation, and `MeasureInteger` assumes that the input is in little endian, so you need to reverse the register before measuring it and coverting results to an integer.
+
+@[solution]({
+    "id": "qft__signal_frequency_solution",
+    "codePath": "./Solution.qs"
+})
diff --git a/katas/content/qft/single_qubit/Placeholder.qs b/katas/content/qft/single_qubit/Placeholder.qs
new file mode 100644
index 00000000..7f83dbcc
--- /dev/null
+++ b/katas/content/qft/single_qubit/Placeholder.qs
@@ -0,0 +1,6 @@
+namespace Kata {
+    operation SingleQubitQFT(q : Qubit) : Unit is Adj + Ctl {
+        // Implement your solution here...
+     
+    }
+}
diff --git a/katas/content/qft/single_qubit/Solution.qs b/katas/content/qft/single_qubit/Solution.qs
new file mode 100644
index 00000000..188f4a6d
--- /dev/null
+++ b/katas/content/qft/single_qubit/Solution.qs
@@ -0,0 +1,5 @@
+namespace Kata {
+    operation SingleQubitQFT(q : Qubit) : Unit is Adj + Ctl {
+        H(q);
+    }
+}
\ No newline at end of file
diff --git a/katas/content/qft/single_qubit/Verification.qs b/katas/content/qft/single_qubit/Verification.qs
new file mode 100644
index 00000000..60acd620
--- /dev/null
+++ b/katas/content/qft/single_qubit/Verification.qs
@@ -0,0 +1,22 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Katas;
+    open Microsoft.Quantum.Math;
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        let solution = qs => Kata.SingleQubitQFT(qs[0]);
+        let reference = qs => H(qs[0]);
+        let isCorrect = CheckOperationsAreEqualStrict(1, solution, reference);
+
+        // Output different feedback to the user depending on whether the solution was correct.
+        if isCorrect {
+            Message("Correct!");
+        } else {
+            Message("Incorrect.");
+            Message("Hint: examine the effect your solution has on the state 0.6|0〉 + 0.8|1〉 and compare it with the effect it " +
+                "is expected to have.");
+            ShowQuantumStateComparison(1, qs => Ry(ArcTan2(0.8, 0.6) * 2.0, qs[0]), solution, reference);
+        }
+        isCorrect
+    }
+}
diff --git a/katas/content/qft/single_qubit/index.md b/katas/content/qft/single_qubit/index.md
new file mode 100644
index 00000000..0160ae19
--- /dev/null
+++ b/katas/content/qft/single_qubit/index.md
@@ -0,0 +1,6 @@
+**Input**: A qubit in state $\ket{\psi} = x_0 \ket{0} + x_1 \ket{1}$.
+
+**Goal**: 
+Apply quantum Fourier transform to this qubit, that is, transform it to a state $\frac1{\sqrt2} \big((x_0 + x_1) \ket{0} + (x_0 - x_1) \ket{1}\big)$.
+
+In other words, transform each basis state $\ket{j}$ into $\frac1{\sqrt2} (\ket{0} + e^{2\pi i \cdot \frac{j}{2}} \ket{1} )$.
\ No newline at end of file
diff --git a/katas/content/qft/single_qubit/solution.md b/katas/content/qft/single_qubit/solution.md
new file mode 100644
index 00000000..300c796f
--- /dev/null
+++ b/katas/content/qft/single_qubit/solution.md
@@ -0,0 +1,11 @@
+The required transformation is actually just the expression for the transformation of an arbitrary state in the $Z$ basis (that is, the computational basis) to one in the $X$ basis (the Hadamard basis). 
+
+For the starting state $\ket{0}$, $x_0=1$ and $x_1=0$, so the new state will be  $\frac1{\sqrt2} (\ket{0} + \ket{1}) = \ket{+}$.
+Similarly, for the starting state $\ket{1}$, $x_0=0$ and $x_1=1$, so the new state will be  $\frac1{\sqrt2} (\ket{0} - \ket{1}) = \ket{-}$.
+
+And you already know a gate that will do this: the Hadamard gate!
+
+@[solution]({
+"id": "qft__single_qubit_solution",
+"codePath": "./Solution.qs"
+})
diff --git a/katas/content/qft/square_wave/Placeholder.qs b/katas/content/qft/square_wave/Placeholder.qs
new file mode 100644
index 00000000..7845798e
--- /dev/null
+++ b/katas/content/qft/square_wave/Placeholder.qs
@@ -0,0 +1,14 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+
+    operation SquareWave(qs : Qubit[]) : Unit is Adj + Ctl {
+        // Implement your solution here...
+
+    }
+
+    // You might find this helper operation that implements QFT using a library operation useful.
+    operation QFT(qs : Qubit[]) : Unit is Adj + Ctl {
+        ApplyQFT(Reversed(qs));
+        SwapReverseRegister(qs);
+    }
+}
diff --git a/katas/content/qft/square_wave/Solution.qs b/katas/content/qft/square_wave/Solution.qs
new file mode 100644
index 00000000..92e2d465
--- /dev/null
+++ b/katas/content/qft/square_wave/Solution.qs
@@ -0,0 +1,18 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+
+    operation SquareWave(qs : Qubit[]) : Unit is Adj + Ctl {
+        X(qs[1]);
+        H(qs[0]);
+        T(qs[0]);
+        X(qs[0]);
+        Adjoint T(qs[0]);
+        X(qs[0]);
+        QFT(qs);
+    }
+
+    operation QFT(qs : Qubit[]) : Unit is Adj + Ctl {
+        ApplyQFT(Reversed(qs));
+        SwapReverseRegister(qs);
+    }
+}
diff --git a/katas/content/qft/square_wave/Verification.qs b/katas/content/qft/square_wave/Verification.qs
new file mode 100644
index 00000000..a09585d2
--- /dev/null
+++ b/katas/content/qft/square_wave/Verification.qs
@@ -0,0 +1,26 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Katas;
+
+    operation SquareWave_Reference (qs : Qubit[]) : Unit is Adj + Ctl {
+        for q in qs {
+            H(q);
+        }
+        Z(qs[Length(qs) - 2]);
+    }
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        for n in 2 .. 5 {
+            let solution = Kata.SquareWave;
+            let reference = SquareWave_Reference;
+            if not CheckOperationsEquivalenceOnZeroState(solution, reference, n) {
+                Message($"Incorrect for {n} qubit(s)");
+                ShowQuantumStateComparison(n, qs => (), solution, reference);
+                return false;
+            }
+        }
+
+        Message("Correct!");
+        return true;
+    }
+}
diff --git a/katas/content/qft/square_wave/index.md b/katas/content/qft/square_wave/index.md
new file mode 100644
index 00000000..12973d81
--- /dev/null
+++ b/katas/content/qft/square_wave/index.md
@@ -0,0 +1,7 @@
+**Input:** $n \ge 2$ qubits in the $\ket{0 \dots 0}$ state.
+
+**Goal:**  Change the state of the qubits to a periodic state with alternating $1, 1, -1, -1$ amplitudes of basis states:
+
+$$\frac1{\sqrt{2^n}} \big(\ket{0} + \ket{1} - \ket{2} - \ket{3} + ... - \ket{2^n-2} - \ket{2^n-1} \big)$$
+
+> For example, for $n = 2$ the goal state is $\frac12 \big(\ket{0} + \ket{1} - \ket{2} - \ket{3}\big)$.
diff --git a/katas/content/qft/square_wave/solution.md b/katas/content/qft/square_wave/solution.md
new file mode 100644
index 00000000..8ae1e475
--- /dev/null
+++ b/katas/content/qft/square_wave/solution.md
@@ -0,0 +1,42 @@
+The target state written in binary notation instead of integers can have its terms grouped in fours that look as follows:
+
+$$ \ket{...00} + \ket{...01} - \ket{...10} - \ket{...11} $$
+
+The states which have $1$ as their second-least significant bit have a $-1$ relative phase, and the states with $0$ in that bit have a $1$ relative phase. Written as a tensor product of single-qubit states, the target state looks as follows:
+
+$$\frac1{\sqrt{2^n}} (\ket{0} + \ket{1}) \otimes (\ket{0} + \ket{1}) \otimes ... \otimes (\ket{0} - \ket{1}) \otimes (\ket{0} + \ket{1})$$
+
+You could try to prepare this state by setting only $j_2$ to $1$ and the rest of bits of $j$ to $0$ and then applying the QFT. This will add the required relative phase of $-1$ on the second-to-last qubit bit, but will also add a relative phase of $i$ on the last qubit bit:
+
+$$QFT(\ket{010...0}) = \frac1{\sqrt{2^n}} (\ket{0} + \ket{1}) \otimes (\ket{0} + \ket{1}) \otimes ... \otimes (\ket{0} - \ket{1}) \otimes (\ket{0} + i\ket{1})$$
+
+To fix this last qubit state, you need to cancel out that last $i$ relative phase in some form. This can be achieved by using the following state as the input to QFT:
+
+$$\frac1{\sqrt2} \big(e^{-i\pi/4} \ket{010...0} + e^{i\pi/4} \ket{110...0}\big)$$
+
+You can write out the result of applying QFT to this state as follows, using the fact that $e^{\pm i\pi/4} = \frac{1 \pm i}{\sqrt2}$:
+
+$$ QFT\bigg(\frac1{\sqrt2} \big(e^{-i\pi/4} \ket{010...0} + e^{i\pi/4} \ket{110...0}\big)\bigg) = \\
+
+= \frac1{\sqrt2}\bigg( \frac{1-i}{\sqrt2} QFT\ket{010...0} + \frac{1+i}{\sqrt2} QFT\ket{110...0} \bigg) = \\
+
+= \frac{(1-i)}{2\sqrt{2^n}} (\ket{0} + \ket{1}) \otimes (\ket{0} + \ket{1}) \otimes ... \otimes (\ket{0} - \ket{1}) \otimes (\ket{0} + i\ket{1}) + \\
+
++ \frac{(1+i)}{2\sqrt{2^n}} (\ket{0} + \ket{1}) \otimes (\ket{0} + \ket{1}) \otimes ... \otimes (\ket{0} - \ket{1}) \otimes (\ket{0} - i\ket{1}) = \\
+
+= \frac{1}{\sqrt{2^{n}}} (\ket{0} + \ket{1}) \otimes (\ket{0} + \ket{1}) \otimes ... \otimes (\ket{0} - \ket{1}) \otimes (\ket{0} + \ket{1})$$
+ 
+Creating the required initial superposition state can be done using the $T$ gate and its adjoint in addition to the more standard $X$ and $H$ gates:
+
+1. Apply an $H$ gate to the first qubit and an $X$ gate to the second qubit:
+   $$\frac1{\sqrt2} \big(\ket{010...0} + \ket{110...0}\big)$$
+2. Add the relative phase $e^{i\pi/4}$ to the second term by applying a $T$ gate to the first qubit:
+   $$\frac1{\sqrt2} \big(\ket{010...0} + e^{i\pi/4} \ket{110...0}\big)$$
+3. Add the relative phase $e^{-i\pi/4}$ to the first term by applying an adjoint $T$ gate wrapped in $X$ gates to the first qubit (this way, the relative phase will be applied to $\ket{0}$ basis state of that qubit):
+   $$\frac1{\sqrt2} \big(e^{-i\pi/4} \ket{010...0} + e^{i\pi/4} \ket{110...0}\big)$$
+
+
+@[solution]({
+    "id": "qft__square_wave_solution",
+    "codePath": "./Solution.qs"
+})
diff --git a/katas/content/solving_graph_coloring/Common.qs b/katas/content/solving_graph_coloring/Common.qs
index 8ba50911..d49f0dc0 100644
--- a/katas/content/solving_graph_coloring/Common.qs
+++ b/katas/content/solving_graph_coloring/Common.qs
@@ -86,4 +86,31 @@ namespace Kata.Verification {
 
         true
     }
+
+    function IsWeakColoringValid_OneVertex_Reference (V : Int, edges: (Int, Int)[], colors: Int[], vertex : Int) : Bool {
+        mutable neighborCount = 0;
+        mutable hasDifferentNeighbor = false;
+
+        for (start, end) in edges {
+            if start == vertex or end == vertex {
+                set neighborCount += 1;
+                if colors[start] != colors[end] {
+                    set hasDifferentNeighbor = true;
+                }
+            }
+        }
+
+        return neighborCount == 0 or hasDifferentNeighbor;
+    }
+
+    function IsWeakColoringValid_Reference (V : Int, edges: (Int, Int)[], colors: Int[]) : Bool {
+        for v in 0 .. V - 1 {
+            if not IsWeakColoringValid_OneVertex_Reference(V, edges, colors, v) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
 }
\ No newline at end of file
diff --git a/katas/content/solving_graph_coloring/examples/SolvingGraphColoringWithGroverDemo.qs b/katas/content/solving_graph_coloring/examples/SolvingGraphColoringWithGroverDemo.qs
new file mode 100644
index 00000000..41d08ffd
--- /dev/null
+++ b/katas/content/solving_graph_coloring/examples/SolvingGraphColoringWithGroverDemo.qs
@@ -0,0 +1,123 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+    open Microsoft.Quantum.Convert;
+    open Microsoft.Quantum.Diagnostics;
+    open Microsoft.Quantum.Math;
+
+    @EntryPoint()
+    operation SolvingGraphColoringWithGroverDemo() : Unit {
+        // Experiment with the parameters to explore algorithm behavior in different conditions!
+        let V = 3;
+        // The 0 -- 1 -- 2 graph from the examples
+        let edges = [(0, 1), (1, 2)];
+        let markingOracle = Oracle_VertexColoring(V, edges, _, _);
+        for iterations in 0 .. 9 {
+            mutable success = 0;
+            for _ in 1 .. 100 {
+                let res = GroversSearch(2 * V, markingOracle, iterations);
+                // Convert measurement results to integers
+                let colorPartitions = Chunks(2, res);
+                let colors = Mapped(bits -> BoolArrayAsInt(Reversed(bits)), colorPartitions);
+                if IsVertexColoringValid(V, edges, colors) {
+                    set success += 1;
+                }
+            }
+            Message($"{iterations} iterations - {success}% success rate");
+        }
+    }
+
+    operation GroversSearch(
+        n : Int,
+        markingOracle : (Qubit[], Qubit) => Unit is Adj + Ctl, 
+        iterations : Int
+    ) : Bool[] {
+        use qs = Qubit[n];
+
+        // Operation that prepares the state |all⟩.
+        let meanStatePrep = ApplyToEachCA(H, _);
+
+        // The phase oracle.
+        let phaseOracle = ApplyMarkingOracleAsPhaseOracle(markingOracle, _);
+
+        // Prepare the system in the state |all⟩.
+        meanStatePrep(qs);
+
+        // Do Grover's iterations.
+        for _ in 1 .. iterations {
+            // Apply the phase oracle.
+            phaseOracle(qs);
+
+            // Apply "reflection about the mean".
+            ReflectionAboutState(qs, meanStatePrep);
+        }
+
+        // Measure to get the result.
+        return ResultArrayAsBoolArray(MResetEachZ(qs));
+    }
+
+    operation ApplyMarkingOracleAsPhaseOracle(
+        markingOracle : (Qubit[], Qubit) => Unit is Adj + Ctl,
+        qubits : Qubit[])
+    : Unit is Adj + Ctl {
+        use minus = Qubit();
+        within {
+            X(minus);
+            H(minus);
+        } apply {
+            markingOracle(qubits, minus);
+        }
+    }
+
+    operation ReflectionAboutState(
+        qs : Qubit[],
+        statePrep : Qubit[] => Unit is Adj + Ctl)
+    : Unit is Adj + Ctl {
+        within {
+            Adjoint statePrep(qs);
+        } apply {
+            ConditionalPhaseFlip(qs);
+        }
+    }
+
+    operation ConditionalPhaseFlip(qs : Qubit[]) : Unit is Adj + Ctl {
+        within {
+            ApplyToEachA(X, qs);
+        } apply {
+            Controlled Z(qs[1 ...], qs[0]);
+        }
+        R(PauliI, 2.0 * PI(), qs[0]);
+    }
+
+    operation Oracle_VertexColoring(V : Int, edges: (Int, Int)[], x : Qubit[], y : Qubit) : Unit is Adj + Ctl {
+        let edgesNumber = Length(edges);
+        use conflicts = Qubit[edgesNumber];
+        within {
+            for i in 0 .. edgesNumber - 1 {
+                let (v0, v1) = edges[i];
+                Oracle_ColorEquality(x[2 * v0 .. 2 * v0 + 1], 
+                                     x[2 * v1 .. 2 * v1 + 1], conflicts[i]);
+            }
+        } apply {
+            ApplyControlledOnInt(0, X, conflicts, y);
+        }
+    }
+
+    operation Oracle_ColorEquality(x0 : Qubit[], x1 : Qubit[], y : Qubit) : Unit is Adj + Ctl {
+        within {
+            for i in 0..Length(x0) - 1 {
+                CNOT(x0[i], x1[i]);
+            }
+        } apply {
+            ApplyControlledOnInt(0, X, x1, y);
+        }
+    }
+
+    function IsVertexColoringValid(V : Int, edges: (Int, Int)[], colors: Int[]) : Bool {
+        for (v0, v1) in edges {
+            if colors[v0] == colors[v1] {
+                return false;
+            }
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/katas/content/solving_graph_coloring/index.md b/katas/content/solving_graph_coloring/index.md
index 43e80aa2..d225e658 100644
--- a/katas/content/solving_graph_coloring/index.md
+++ b/katas/content/solving_graph_coloring/index.md
@@ -64,7 +64,28 @@ In this lesson, you will implement the marking oracle for the vertex coloring pr
     "title": "Weak Coloring Problem"
 })
 
-TODO: finish migration
+Weak graph coloring is a coloring of graph vertices which labels each vertex with one of the given colors in such a way that each non-isolated vertex is connected by an edge to at least one neighbor of a different color.
+
+In this lesson, you will implement the marking oracle for the weak graph coloring problem.
+
+@[exercise]({
+    "id": "solving_graph_coloring__weak_coloring_classical",
+    "title": "Is Weak Coloring Valid? (Classical)",
+    "path": "./weak_coloring_classical/"
+})
+
+@[exercise]({
+    "id": "solving_graph_coloring__weak_coloring_one_vertex",
+    "title": "Is One-Vertex Weak Coloring Valid? (Quantum)",
+    "path": "./weak_coloring_one_vertex/"
+})
+
+@[exercise]({
+    "id": "solving_graph_coloring__weak_coloring_quantum",
+    "title": "Is Weak Coloring Valid? (Quantum)",
+    "path": "./weak_coloring/"
+})
+
 
 
 @[section]({
@@ -74,10 +95,16 @@ TODO: finish migration
 
 In this lesson, you will experiment with using Grover's algorithm to solve graph coloring problems.
 
-Notice that in this case, it's not as easy to know the number of solutions to the problem upfront as it was for the prefix function used in the "Grover's Search Algorithm" kata.
+In this case, it's not as easy to know the number of solutions to the problem upfront as it was for the prefix function used in the "Grover's Search Algorithm" kata.
 Experiment with choosing the number of iterations at random. How does this affect the success probability?
 
-TODO: add demo
+> Notice that the example used in this demo, a three-vertex graph with two edges, has the search space of size $4^3 = 64$.
+> A bit over half of the colorings in the search space are valid vertex colorings. You can count them by assigning any color to vertex $1$ and then assigning any of the remaining three colors to vertices $0$ and $2$ independently, to get $4 \cdot 3 \cdot 3 = 36$ solutions to the problem.
+> This example is one of the scenarios in which Grover's search behaves in a non-intuitive way: not doing any iterations 
+> yields a success probability of over $50\%$, so the first iteration actually reduces the probability of getting a correct answer!
+
+@[example]({"id": "solving_graph_coloring__e2edemo", "codePath": "./examples/SolvingGraphColoringWithGroverDemo.qs"})
+
 
 @[section]({
     "id": "solving_graph_coloring__conclusion",
diff --git a/katas/content/solving_graph_coloring/vertex_coloring_classical/index.md b/katas/content/solving_graph_coloring/vertex_coloring_classical/index.md
index 86676a2e..4668d3e0 100644
--- a/katas/content/solving_graph_coloring/vertex_coloring_classical/index.md
+++ b/katas/content/solving_graph_coloring/vertex_coloring_classical/index.md
@@ -5,7 +5,7 @@
 Each tuple gives the indices of the start and the end vertices of the edge.
 The vertices are numbered $0$ through $V - 1$.
 3. An array of $V$ integers, representing the vertex coloring of the graph. 
-$i$-th element of the array is the color of the vertex number $i$.
+The $i$-th element of the array is the color of the vertex number $i$.
 
 For example, the graph `0 -- 1 -- 2` has $V = 3$ and `edges = [(0, 1), (1, 2)]`. 
 Some of the valid colorings for it would be `[0, 1, 0]` and `[-1, 5, 18]`.
diff --git a/katas/content/solving_graph_coloring/weak_coloring/Placeholder.qs b/katas/content/solving_graph_coloring/weak_coloring/Placeholder.qs
new file mode 100644
index 00000000..89fdd564
--- /dev/null
+++ b/katas/content/solving_graph_coloring/weak_coloring/Placeholder.qs
@@ -0,0 +1,41 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+
+    operation Oracle_WeakColoring(
+        V : Int, edges: (Int, Int)[], x : Qubit[], y : Qubit
+    ) : Unit is Adj + Ctl {
+        // Implement your solution here...
+
+    }
+
+    // You might find these helper operations from earlier tasks useful.
+    operation Oracle_WeakColoring_OneVertex(
+        V : Int, edges: (Int, Int)[], x : Qubit[], y : Qubit, vertex : Int
+    ) : Unit is Adj + Ctl {
+        let neighborEdges = Filtered((a, b) -> a == vertex or b == vertex, edges);
+        let nNeighbors = Length(neighborEdges);
+        use sameColorChecks = Qubit[nNeighbors];
+        within {
+            for ((a, b), checkQubit) in Zipped(neighborEdges, sameColorChecks) {
+                Oracle_ColorEquality(x[a * 2 .. a * 2 + 1],
+                                     x[b * 2 .. b * 2 + 1], 
+                                     checkQubit);
+            }
+        } apply {
+            X(y);
+            if nNeighbors > 0 {
+                Controlled X(sameColorChecks, y);
+            }
+        }
+    }
+
+    operation Oracle_ColorEquality(x0 : Qubit[], x1 : Qubit[], y : Qubit) : Unit is Adj + Ctl {
+        within {
+            for i in 0..Length(x0) - 1 {
+                CNOT(x0[i], x1[i]);
+            }
+        } apply {
+            ApplyControlledOnInt(0, X, x1, y);
+        }
+    }
+}
diff --git a/katas/content/solving_graph_coloring/weak_coloring/Solution.qs b/katas/content/solving_graph_coloring/weak_coloring/Solution.qs
new file mode 100644
index 00000000..ac203c86
--- /dev/null
+++ b/katas/content/solving_graph_coloring/weak_coloring/Solution.qs
@@ -0,0 +1,47 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+
+    operation Oracle_WeakColoring(
+        V : Int, edges: (Int, Int)[], x : Qubit[], y : Qubit
+    ) : Unit is Adj + Ctl {
+        use vertexQubits = Qubit[V];
+        within {
+            for v in 0 .. V - 1 {
+                Oracle_WeakColoring_OneVertex(V, edges, x, vertexQubits[v], v);
+            }
+        } apply {
+            Controlled X(vertexQubits, y);
+        }
+    }
+
+    // You might find these helper operations from earlier tasks useful.
+    operation Oracle_WeakColoring_OneVertex(
+        V : Int, edges: (Int, Int)[], x : Qubit[], y : Qubit, vertex : Int
+    ) : Unit is Adj + Ctl {
+        let neighborEdges = Filtered((a, b) -> a == vertex or b == vertex, edges);
+        let nNeighbors = Length(neighborEdges);
+        use sameColorChecks = Qubit[nNeighbors];
+        within {
+            for ((a, b), checkQubit) in Zipped(neighborEdges, sameColorChecks) {
+                Oracle_ColorEquality(x[a * 2 .. a * 2 + 1],
+                                     x[b * 2 .. b * 2 + 1], 
+                                     checkQubit);
+            }
+        } apply {
+            X(y);
+            if nNeighbors > 0 {
+                Controlled X(sameColorChecks, y);
+            }
+        }
+    }
+
+    operation Oracle_ColorEquality(x0 : Qubit[], x1 : Qubit[], y : Qubit) : Unit is Adj + Ctl {
+        within {
+            for i in 0..Length(x0) - 1 {
+                CNOT(x0[i], x1[i]);
+            }
+        } apply {
+            ApplyControlledOnInt(0, X, x1, y);
+        }
+    }
+}
diff --git a/katas/content/solving_graph_coloring/weak_coloring/Verification.qs b/katas/content/solving_graph_coloring/weak_coloring/Verification.qs
new file mode 100644
index 00000000..1861edf2
--- /dev/null
+++ b/katas/content/solving_graph_coloring/weak_coloring/Verification.qs
@@ -0,0 +1,18 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Arrays;
+    open Microsoft.Quantum.Katas;
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        for (V, edges) in Most(ExampleGraphs()) {
+            if not CheckOracleRecognizesColoring(V, edges, 
+                Kata.Oracle_WeakColoring, IsWeakColoringValid_Reference
+            ) {
+                return false;
+            }
+        }
+
+        Message("Correct!");
+        true
+    }
+}
diff --git a/katas/content/solving_graph_coloring/weak_coloring/index.md b/katas/content/solving_graph_coloring/weak_coloring/index.md
new file mode 100644
index 00000000..371e4c8d
--- /dev/null
+++ b/katas/content/solving_graph_coloring/weak_coloring/index.md
@@ -0,0 +1,15 @@
+**Inputs:**
+
+1. The number of vertices in the graph $V$ ($V \leq 6$).
+2. An array of $E$ tuples of integers, representing the edges of the graph ($E \leq 12$).
+Each tuple gives the indices of the start and the end vertices of the edge.
+The vertices are numbered $0$ through $V - 1$.
+3. An array of $2V$ qubits in an arbitrary state $\ket{x}$ representing the assigned coloring of the vertices using four colors ($nBits = 2$) in the same format as in the exercise "Read Coloring From a Qubit Array".
+4. A qubit in an arbitrary state $\ket{y}$ (output/target qubit).
+
+**Goal:**
+Implement a quantum oracle which checks whether the given weak coloring is valid for the given graph,
+that is, whether each vertex of the graph is either isolated or connected to at least one vertex of a different color.
+    
+Leave the qubits in the input register in the same state they started in.
+Your solution should work on inputs in superposition, and not use any measurements.
\ No newline at end of file
diff --git a/katas/content/solving_graph_coloring/weak_coloring/solution.md b/katas/content/solving_graph_coloring/weak_coloring/solution.md
new file mode 100644
index 00000000..75de2c72
--- /dev/null
+++ b/katas/content/solving_graph_coloring/weak_coloring/solution.md
@@ -0,0 +1,9 @@
+To implement this oracle, you need to check whether each vertex is colored correctly and combine the results of individual checks. You'll need to allocate an array of qubits, one per vertex, that will be flipped if the corresponding vertex is weakly colored.
+This can be done easily using the `Oracle_WeakColoring_OneVertex` operation defined in the previous task. Then, you need to check if all qubits in the array is in state $\ket{1...1}$ using the Controlled $X$ gate; if they are, the coloring is valid.
+
+As usual, remember to uncompute the changes to the auxiliary qubits after you evaluate the final result to leave them clean before their release.
+
+@[solution]({
+    "id": "solving_graph_coloring__weak_coloring_quantum_solution",
+    "codePath": "./Solution.qs"
+})
diff --git a/katas/content/solving_graph_coloring/weak_coloring_classical/Placeholder.qs b/katas/content/solving_graph_coloring/weak_coloring_classical/Placeholder.qs
new file mode 100644
index 00000000..543861a1
--- /dev/null
+++ b/katas/content/solving_graph_coloring/weak_coloring_classical/Placeholder.qs
@@ -0,0 +1,7 @@
+namespace Kata {
+    function IsWeakColoringValid(V : Int, edges: (Int, Int)[], colors: Int[]) : Bool {
+        // Implement your solution here...
+
+        return false;
+    }
+}
diff --git a/katas/content/solving_graph_coloring/weak_coloring_classical/Solution.qs b/katas/content/solving_graph_coloring/weak_coloring_classical/Solution.qs
new file mode 100644
index 00000000..7b2481a3
--- /dev/null
+++ b/katas/content/solving_graph_coloring/weak_coloring_classical/Solution.qs
@@ -0,0 +1,22 @@
+namespace Kata {
+    function IsWeakColoringValid(V : Int, edges: (Int, Int)[], colors: Int[]) : Bool {
+        for vertex in 0 .. V - 1 {
+            mutable neighborCount = 0;
+            mutable hasDifferentNeighbor = false;
+
+            for (start, end) in edges {
+                if start == vertex or end == vertex {
+                    set neighborCount += 1;
+                    if colors[start] != colors[end] {
+                        set hasDifferentNeighbor = true;
+                    }
+                }
+            }
+
+            if neighborCount > 0 and not hasDifferentNeighbor {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/katas/content/solving_graph_coloring/weak_coloring_classical/Verification.qs b/katas/content/solving_graph_coloring/weak_coloring_classical/Verification.qs
new file mode 100644
index 00000000..c68d4e7a
--- /dev/null
+++ b/katas/content/solving_graph_coloring/weak_coloring_classical/Verification.qs
@@ -0,0 +1,34 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Arrays;
+    open Microsoft.Quantum.Katas;
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        let testGraphs = ExampleGraphs()[0 .. 4];
+        let testColorings = [
+            // Every coloring would pass on a disconnected graph of 3 vertices
+            [([0, 0, 0], true), ([2, 1, 3], true)],
+            // Every coloring  would pass on a fully connected graph of 4 vertices,
+            // except for the last coloring in which all vertices are of the same color.
+            [([0, 2, 1, 3], true), ([3, 0, 1, 0], true), ([0, 0, 0, 0], false)],
+            // The colorings for 5-vertex graphs:
+            // - the first one is invalid for all graphs except disconnected
+            // - the second one is valid for all types of graphs regardless of their structure
+            // - two colorings that is valid or invalid depending on the graph
+            [([0, 0, 0, 0, 0], false), ([0, 1, 2, 3, 4], true), ([0, 1, 1, 2, 0], false), ([0, 0, 1, 1, 1], true)],
+            [([0, 0, 0, 0, 0], false), ([0, 1, 2, 3, 4], true), ([0, 1, 1, 2, 0], true), ([0, 0, 1, 1, 1], false)],
+            [([0, 0, 0, 0, 0], false), ([0, 1, 2, 3, 4], true), ([0, 1, 1, 2, 0], true), ([0, 0, 1, 1, 1], true)]
+        ];
+        for ((V, edges), colorings) in Zipped(testGraphs, testColorings) {
+            for (coloring, expected) in colorings {
+                if Kata.IsWeakColoringValid(V, edges, coloring) != expected {
+                    Message($"Weak coloring {coloring} evaluated incorrectly for graph V = {V}, edges = {edges}: expected {expected}");
+                    return false;
+                }
+            }
+        }
+
+        Message("Correct!");
+        true
+    }
+}
diff --git a/katas/content/solving_graph_coloring/weak_coloring_classical/index.md b/katas/content/solving_graph_coloring/weak_coloring_classical/index.md
new file mode 100644
index 00000000..61df0d84
--- /dev/null
+++ b/katas/content/solving_graph_coloring/weak_coloring_classical/index.md
@@ -0,0 +1,14 @@
+**Inputs:**
+
+1. The number of vertices in the graph $V$ ($V \leq 6$).
+2. An array of $E$ tuples of integers, representing the edges of the graph ($E \leq 12$).
+Each tuple gives the indices of the start and the end vertices of the edge.
+The vertices are numbered $0$ through $V - 1$.
+3. An array of $V$ integers, representing the vertex coloring of the graph. 
+The $i$-th element of the array is the color of the vertex number $i$.
+
+For example, consider the triangular graph `0 -- 1 -- 2 -- 0` with $V = 3$ and `edges = [(0, 1), (1, 2), (0, 2)]`. 
+The coloring `[0, 1, 0]` is a valid weak coloring for it despite the fact that the connected vertices $0$ and $2$ are assigned the same color, since each of them is also connected to the vertex $1$ of a different color.
+
+**Output:**
+True if the given weak coloring is valid (that is, each vertex either has no neighbors, or has at least one neighbor of a different color), and false otherwise.
\ No newline at end of file
diff --git a/katas/content/solving_graph_coloring/weak_coloring_classical/solution.md b/katas/content/solving_graph_coloring/weak_coloring_classical/solution.md
new file mode 100644
index 00000000..174fefd3
--- /dev/null
+++ b/katas/content/solving_graph_coloring/weak_coloring_classical/solution.md
@@ -0,0 +1,6 @@
+A weak coloring is valid when each of the vertices is weakly colored, that is, has either no neighbors or has at least one neighbor of a different color. This means that the solution needs to iterate through all vertices and check this condition for each of them, tracking separately the number of vertices connected to it with an edge and the existence of a connected vertex of a different color.
+
+@[solution]({
+    "id": "solving_graph_coloring__weak_coloring_classical_solution",
+    "codePath": "./Solution.qs"
+})
diff --git a/katas/content/solving_graph_coloring/weak_coloring_one_vertex/Placeholder.qs b/katas/content/solving_graph_coloring/weak_coloring_one_vertex/Placeholder.qs
new file mode 100644
index 00000000..d439f53e
--- /dev/null
+++ b/katas/content/solving_graph_coloring/weak_coloring_one_vertex/Placeholder.qs
@@ -0,0 +1,19 @@
+namespace Kata {
+    operation Oracle_WeakColoring_OneVertex(
+        V : Int, edges: (Int, Int)[], x : Qubit[], y : Qubit, vertex : Int
+    ) : Unit is Adj + Ctl {
+        // Implement your solution here...
+
+    }
+
+    // You might find this helper operation from an earlier task useful.
+    operation Oracle_ColorEquality(x0 : Qubit[], x1 : Qubit[], y : Qubit) : Unit is Adj + Ctl {
+        within {
+            for i in 0..Length(x0) - 1 {
+                CNOT(x0[i], x1[i]);
+            }
+        } apply {
+            ApplyControlledOnInt(0, X, x1, y);
+        }
+    }
+}
diff --git a/katas/content/solving_graph_coloring/weak_coloring_one_vertex/Solution.qs b/katas/content/solving_graph_coloring/weak_coloring_one_vertex/Solution.qs
new file mode 100644
index 00000000..a801a735
--- /dev/null
+++ b/katas/content/solving_graph_coloring/weak_coloring_one_vertex/Solution.qs
@@ -0,0 +1,33 @@
+namespace Kata {
+    open Microsoft.Quantum.Arrays;
+
+    operation Oracle_WeakColoring_OneVertex(
+        V : Int, edges: (Int, Int)[], x : Qubit[], y : Qubit, vertex : Int
+    ) : Unit is Adj + Ctl {
+        let neighborEdges = Filtered((a, b) -> a == vertex or b == vertex, edges);
+        let nNeighbors = Length(neighborEdges);
+        use sameColorChecks = Qubit[nNeighbors];
+        within {
+            for ((a, b), checkQubit) in Zipped(neighborEdges, sameColorChecks) {
+                Oracle_ColorEquality(x[a * 2 .. a * 2 + 1],
+                                     x[b * 2 .. b * 2 + 1], 
+                                     checkQubit);
+            }
+        } apply {
+            X(y);
+            if nNeighbors > 0 {
+                Controlled X(sameColorChecks, y);
+            }
+        }
+    }
+
+    operation Oracle_ColorEquality(x0 : Qubit[], x1 : Qubit[], y : Qubit) : Unit is Adj + Ctl {
+        within {
+            for i in 0..Length(x0) - 1 {
+                CNOT(x0[i], x1[i]);
+            }
+        } apply {
+            ApplyControlledOnInt(0, X, x1, y);
+        }
+    }
+}
diff --git a/katas/content/solving_graph_coloring/weak_coloring_one_vertex/Verification.qs b/katas/content/solving_graph_coloring/weak_coloring_one_vertex/Verification.qs
new file mode 100644
index 00000000..ca06b21f
--- /dev/null
+++ b/katas/content/solving_graph_coloring/weak_coloring_one_vertex/Verification.qs
@@ -0,0 +1,22 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Arrays;
+    open Microsoft.Quantum.Katas;
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        for (V, edges) in Most(ExampleGraphs()) {
+            for vertex in 0 .. V - 1 {
+                if not CheckOracleRecognizesColoring(V, edges, 
+                    Kata.Oracle_WeakColoring_OneVertex(_, _, _, _, vertex), 
+                    IsWeakColoringValid_OneVertex_Reference(_, _, _, vertex)
+                ) {
+                    Message($"Testing vertex {vertex}");
+                    return false;
+                }
+            }
+        }
+
+        Message("Correct!");
+        true
+    }
+}
diff --git a/katas/content/solving_graph_coloring/weak_coloring_one_vertex/index.md b/katas/content/solving_graph_coloring/weak_coloring_one_vertex/index.md
new file mode 100644
index 00000000..4d519e7c
--- /dev/null
+++ b/katas/content/solving_graph_coloring/weak_coloring_one_vertex/index.md
@@ -0,0 +1,16 @@
+**Inputs:**
+
+1. The number of vertices in the graph $V$ ($V \leq 6$).
+2. An array of $E$ tuples of integers, representing the edges of the graph ($E \leq 12$).
+Each tuple gives the indices of the start and the end vertices of the edge.
+The vertices are numbered $0$ through $V - 1$.
+3. An array of $2V$ qubits in an arbitrary state $\ket{x}$ representing the assigned coloring of the vertices using four colors ($nBits = 2$) in the same format as in the exercise "Read Coloring From a Qubit Array".
+4. A qubit in an arbitrary state $\ket{y}$ (output/target qubit).
+5. An index of a vertex in the graph between $0$ and $V - 1$, inclusive.
+
+**Goal:**
+Implement a quantum oracle which checks whether the given vertex is weakly colored in the given coloring of the given graph,
+that is, whether it is either isolated or is connected to at least one vertex of a different color.
+    
+Leave the qubits in the input register in the same state they started in.
+Your solution should work on inputs in superposition, and not use any measurements.
\ No newline at end of file
diff --git a/katas/content/solving_graph_coloring/weak_coloring_one_vertex/solution.md b/katas/content/solving_graph_coloring/weak_coloring_one_vertex/solution.md
new file mode 100644
index 00000000..b9725734
--- /dev/null
+++ b/katas/content/solving_graph_coloring/weak_coloring_one_vertex/solution.md
@@ -0,0 +1,12 @@
+To implement this check, you need to start by counting the vertices connected to the given vertex 
+and allocating an array of auxiliary qubits, one for each neighboring vertex. These qubits will have their states flipped if the vertices connected by the corresponding edge have the same color. 
+This can be done easily using with the operation `Oracle_ColorEquality` from an earlier task, similarly to how you did in when validating the vertex coloring of the graph. 
+
+Now, for the coloring of the vertex to be valid, it needs to either have no neighbors, or to have at least one neighbor of a different color, so the array of auxiliary qubits should be in any state but $\ket{1...1}$. To implement this, you can flip the target qubit $\ket{y}$ unconditionally using the $X$ gate, and then flip it again only if qubits are in state $\ket{1...1}$.
+
+Make sure to uncompute the changes to the auxiliary qubits after you evaluate the final result to leave them clean before their release.
+
+@[solution]({
+    "id": "solving_graph_coloring__weak_coloring_one_vertex_solution",
+    "codePath": "./Solution.qs"
+})
diff --git a/language_service/src/name_locator.rs b/language_service/src/name_locator.rs
index 4b486fa4..b99e09ce 100644
--- a/language_service/src/name_locator.rs
+++ b/language_service/src/name_locator.rs
@@ -361,7 +361,7 @@ impl<'inner, 'package, T: Handler<'package>> Visitor<'package> for Locator<'inne
                         }
                     }
 
-                    for field in fields.iter() {
+                    for field in &**fields {
                         if field.span.touches(self.offset) {
                             if field.field.span.touches(self.offset) {
                                 if let Some(hir::ty::Ty::Udt(_, res)) =
diff --git a/language_service/src/references.rs b/language_service/src/references.rs
index 46e4c319..a489dd70 100644
--- a/language_service/src/references.rs
+++ b/language_service/src/references.rs
@@ -414,7 +414,7 @@ impl<'a> Visitor<'_> for FindFieldRefs<'a> {
                 if let Some(copy) = copy {
                     self.visit_expr(copy);
                 }
-                for field in fields.iter() {
+                for field in &**fields {
                     if field.field.name == self.field_name {
                         if let Some(Ty::Udt(_, Res::Item(id))) = self.compilation.get_ty(expr.id) {
                             if self.eq(id) {
diff --git a/library/qs_source/core/core.qs b/library/core/core.qs
similarity index 100%
rename from library/qs_source/core/core.qs
rename to library/core/core.qs
diff --git a/library/qs_source/core/qir.qs b/library/core/qir.qs
similarity index 100%
rename from library/qs_source/core/qir.qs
rename to library/core/qir.qs
diff --git a/library/qs_source/qsharp.json b/library/qs_source/qsharp.json
deleted file mode 100644
index 0967ef42..00000000
--- a/library/qs_source/qsharp.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{}
diff --git a/library/src/README.md b/library/src/README.md
new file mode 100644
index 00000000..507f4a94
--- /dev/null
+++ b/library/src/README.md
@@ -0,0 +1,3 @@
+# Library Rust Crate
+
+This crate is used for packaging and testing our Q# projects in a Rust environment.
\ No newline at end of file
diff --git a/library/src/lib.rs b/library/src/lib.rs
index de58fef9..bef83465 100644
--- a/library/src/lib.rs
+++ b/library/src/lib.rs
@@ -12,85 +12,85 @@ pub const QSHARP_LIBRARY_URI_SCHEME: &str = "qsharp-library-source";
 pub const CORE_LIB: &[(&str, &str)] = &[
     (
         "qsharp-library-source:core/core.qs",
-        include_str!("../qs_source/core/core.qs"),
+        include_str!("../core/core.qs"),
     ),
     (
         "qsharp-library-source:core/qir.qs",
-        include_str!("../qs_source/core/qir.qs"),
+        include_str!("../core/qir.qs"),
     ),
 ];
 
 pub const STD_LIB: &[(&str, &str)] = &[
     (
         "qsharp-library-source:arrays.qs",
-        include_str!("../qs_source/src/std/arrays.qs"),
+        include_str!("../std/src/arrays.qs"),
     ),
     (
         "qsharp-library-source:canon.qs",
-        include_str!("../qs_source/src/std/canon.qs"),
+        include_str!("../std/src/canon.qs"),
     ),
     (
         "qsharp-library-source:convert.qs",
-        include_str!("../qs_source/src/std/convert.qs"),
+        include_str!("../std/src/convert.qs"),
     ),
     (
         "qsharp-library-source:core.qs",
-        include_str!("../qs_source/src/std/core.qs"),
+        include_str!("../std/src/core.qs"),
     ),
     (
         "qsharp-library-source:diagnostics.qs",
-        include_str!("../qs_source/src/std/diagnostics.qs"),
+        include_str!("../std/src/diagnostics.qs"),
     ),
     (
         "qsharp-library-source:internal.qs",
-        include_str!("../qs_source/src/std/internal.qs"),
+        include_str!("../std/src/internal.qs"),
     ),
     (
         "qsharp-library-source:intrinsic.qs",
-        include_str!("../qs_source/src/std/intrinsic.qs"),
+        include_str!("../std/src/intrinsic.qs"),
     ),
     (
         "qsharp-library-source:logical.qs",
-        include_str!("../qs_source/src/std/logical.qs"),
+        include_str!("../std/src/logical.qs"),
     ),
     (
         "qsharp-library-source:math.qs",
-        include_str!("../qs_source/src/std/math.qs"),
+        include_str!("../std/src/math.qs"),
     ),
     (
         "qsharp-library-source:measurement.qs",
-        include_str!("../qs_source/src/std/measurement.qs"),
+        include_str!("../std/src/measurement.qs"),
     ),
     (
         "qsharp-library-source:qir.qs",
-        include_str!("../qs_source/src/std/qir.qs"),
+        include_str!("../std/src/qir.qs"),
     ),
     (
         "qsharp-library-source:random.qs",
-        include_str!("../qs_source/src/std/random.qs"),
+        include_str!("../std/src/random.qs"),
     ),
     (
         "qsharp-library-source:re.qs",
-        include_str!("../qs_source/src/std/re.qs"),
+        include_str!("../std/src/re.qs"),
     ),
     (
         "qsharp-library-source:unstable_arithmetic.qs",
-        include_str!("../qs_source/src/std/unstable_arithmetic.qs"),
+        include_str!("../std/src/unstable_arithmetic.qs"),
     ),
     (
         "qsharp-library-source:unstable_arithmetic_internal.qs",
-        include_str!("../qs_source/src/std/unstable_arithmetic_internal.qs"),
+        include_str!("../std/src/unstable_arithmetic_internal.qs"),
     ),
     (
         "qsharp-library-source:unstable_state_preparation.qs",
-        include_str!("../qs_source/src/std/unstable_state_preparation.qs"),
+        include_str!("../std/src/unstable_state_preparation.qs"),
     ),
     (
         "qsharp-library-source:unstable_table_lookup.qs",
-        include_str!("../qs_source/src/std/unstable_table_lookup.qs"),
+        include_str!("../std/src/unstable_table_lookup.qs"),
     ),
     (
         "qsharp-library-source:modern_api.qs",
-        include_str!("../qs_source/src/std/modern_api.qs"),
+        include_str!("../std/src/modern_api.qs"),
     ),
 ];
diff --git a/library/README.md b/library/std/README.md
similarity index 100%
rename from library/README.md
rename to library/std/README.md
diff --git a/library/std/qsharp.json b/library/std/qsharp.json
new file mode 100644
index 00000000..ed9a1ca5
--- /dev/null
+++ b/library/std/qsharp.json
@@ -0,0 +1,24 @@
+{
+  "author": "Microsoft",
+  "license": "MIT",
+  "files": [
+    "src/std/arrays.qs",
+    "src/std/canon.qs",
+    "src/std/convert.qs",
+    "src/std/core.qs",
+    "src/std/diagnostics.qs",
+    "src/std/internal.qs",
+    "src/std/intrinsic.qs",
+    "src/std/logical.qs",
+    "src/std/math.qs",
+    "src/std/measurement.qs",
+    "src/std/modern_api.qs",
+    "src/std/qir.qs",
+    "src/std/random.qs",
+    "src/std/re.qs",
+    "src/std/unstable_arithmetic.qs",
+    "src/std/unstable_arithmetic_internal.qs",
+    "src/std/unstable_state_preparation.qs",
+    "src/std/unstable_table_lookup.qs"
+  ]
+}
\ No newline at end of file
diff --git a/library/qs_source/src/std/arrays.qs b/library/std/src/arrays.qs
similarity index 100%
rename from library/qs_source/src/std/arrays.qs
rename to library/std/src/arrays.qs
diff --git a/library/qs_source/src/std/canon.qs b/library/std/src/canon.qs
similarity index 97%
rename from library/qs_source/src/std/canon.qs
rename to library/std/src/canon.qs
index 727c672a..6bccc1c1 100644
--- a/library/qs_source/src/std/canon.qs
+++ b/library/std/src/canon.qs
@@ -489,17 +489,22 @@ namespace Microsoft.Quantum.Canon {
     }
 
     /// # Summary
-    /// Applies Quantum Fourier Transform (QFT) to a little-endian quantum register.
+    /// Applies the rotations of Quantum Fourier Transform (QFT) to a little-endian quantum register.
     ///
     /// # Description
-    /// Applies QFT to a little-endian register `qs` of length n
-    /// containing |x₁⟩⊗|x₂⟩⊗…⊗|xₙ⟩. The qs[0] contains the
+    /// Applies the rotations of QFT to a little-endian register `qs` of length n
+    /// containing |x₁⟩⊗|x₂⟩⊗…⊗|xₙ⟩. The qs[0] initially contains the
     /// least significant bit xₙ. The state of qs[0] becomes
     /// (|0⟩+𝑒^(2π𝑖[0.xₙ])|1⟩)/sqrt(2) after the operation.
     ///
     /// # Input
     /// ## qs
-    /// Quantum register in a little-endian format to which the QFT is applied.
+    /// Quantum register in a little-endian format to which the rotations are applied.
+    ///
+    /// # Remarks
+    /// Note that this operation applies only the rotations part of the QFT.
+    /// To complete the transform, you need to reverse the order of qubits after this operation,
+    /// for example, using the operation `SwapReverseRegister`.
     ///
     /// # Reference
     ///  - [Quantum Fourier transform](https://en.wikipedia.org/wiki/Quantum_Fourier_transform)
diff --git a/prereqs.py b/prereqs.py
index d7907a1e..c9fb2d4f 100755
--- a/prereqs.py
+++ b/prereqs.py
@@ -13,14 +13,14 @@ import tempfile
 import functools
 
 python_ver = (3, 11)  # Python support for Windows on ARM64 requires v3.11 or later
-rust_ver = (1, 78)  # Ensure Rust version 1.78 or later is installed
+rust_ver = (1, 80)  # Ensure Rust version 1.80 or later is installed
 node_ver = (
     18,
     17,
 )
 wasmpack_ver = (0, 12, 1)  # Latest tested wasm-pack version
-rust_fmt_ver = (1, 7, 0)  # Current version when Rust 1.78 shipped
-clippy_ver = (0, 1, 78)
+rust_fmt_ver = (1, 7, 0)  # Current version when Rust 1.80 shipped
+clippy_ver = (0, 1, 80)
 
 # Disable buffered output so that the log statements and subprocess output get interleaved in proper order
 print = functools.partial(print, flush=True)


Test patch:
diff --git a/compiler/qsc/src/packages/tests.rs b/compiler/qsc/src/packages/tests.rs
index b34206e8..6bfcf44f 100644
--- a/compiler/qsc/src/packages/tests.rs
+++ b/compiler/qsc/src/packages/tests.rs
@@ -191,6 +191,7 @@ fn missing_dependency_doesnt_force_failure() {
     .assert_debug_eq(&errors);
 }
 
+#[allow(clippy::too_many_lines)]
 #[test]
 fn dependency_error() {
     let mut program = mock_program();
@@ -210,33 +211,58 @@ fn dependency_error() {
     );
 
     expect![[r#"
-            [
-                WithSource {
-                    sources: [
-                        Source {
-                            name: "librarymain",
-                            contents: "broken_syntax",
-                            offset: 0,
-                        },
-                    ],
-                    error: Frontend(
-                        Error(
-                            Parse(
-                                Error(
-                                    ExpectedItem(
-                                        Ident,
-                                        Span {
-                                            lo: 0,
-                                            hi: 0,
-                                        },
-                                    ),
+        [
+            WithSource {
+                sources: [
+                    Source {
+                        name: "librarymain",
+                        contents: "broken_syntax",
+                        offset: 0,
+                    },
+                ],
+                error: Frontend(
+                    Error(
+                        Parse(
+                            Error(
+                                Token(
+                                    Eof,
+                                    Ident,
+                                    Span {
+                                        lo: 0,
+                                        hi: 13,
+                                    },
                                 ),
                             ),
                         ),
                     ),
-                },
-            ]
-        "#]]
+                ),
+            },
+            WithSource {
+                sources: [
+                    Source {
+                        name: "librarymain",
+                        contents: "broken_syntax",
+                        offset: 0,
+                    },
+                ],
+                error: Frontend(
+                    Error(
+                        Parse(
+                            Error(
+                                ExpectedItem(
+                                    Eof,
+                                    Span {
+                                        lo: 0,
+                                        hi: 13,
+                                    },
+                                ),
+                            ),
+                        ),
+                    ),
+                ),
+            },
+        ]
+    "#]]
     .assert_debug_eq(&buildable_program.dependency_errors);
 
     // compile the user code
diff --git a/compiler/qsc_parse/src/tests/implicit_namespace.rs b/compiler/qsc_parse/src/tests/implicit_namespace.rs
index 643765e5..a0816f9d 100644
--- a/compiler/qsc_parse/src/tests/implicit_namespace.rs
+++ b/compiler/qsc_parse/src/tests/implicit_namespace.rs
@@ -232,3 +232,171 @@ fn reject_bad_namespace_name_starts_with_number() {
         )"#]]
     .assert_eq(&result);
 }
+
+#[test]
+fn implicit_namespace_with_incomplete_items() {
+    let result = format!(
+        "{:#?}",
+        crate::namespaces(
+            "
+operation Main() : Unit {}
+oper",
+            Some("code/src/Foo.qs"),
+            LanguageFeatures::default()
+        )
+    );
+    expect![[r#"
+        (
+            [
+                Namespace {
+                    id: NodeId(
+                        4294967295,
+                    ),
+                    span: Span {
+                        lo: 1,
+                        hi: 32,
+                    },
+                    doc: "",
+                    name: Idents(
+                        [
+                            Ident {
+                                id: NodeId(
+                                    4294967295,
+                                ),
+                                span: Span {
+                                    lo: 1,
+                                    hi: 32,
+                                },
+                                name: "code",
+                            },
+                            Ident {
+                                id: NodeId(
+                                    4294967295,
+                                ),
+                                span: Span {
+                                    lo: 1,
+                                    hi: 32,
+                                },
+                                name: "src",
+                            },
+                            Ident {
+                                id: NodeId(
+                                    4294967295,
+                                ),
+                                span: Span {
+                                    lo: 1,
+                                    hi: 32,
+                                },
+                                name: "Foo",
+                            },
+                        ],
+                    ),
+                    items: [
+                        Item {
+                            id: NodeId(
+                                4294967295,
+                            ),
+                            span: Span {
+                                lo: 0,
+                                hi: 27,
+                            },
+                            doc: "",
+                            attrs: [],
+                            kind: Callable(
+                                CallableDecl {
+                                    id: NodeId(
+                                        4294967295,
+                                    ),
+                                    span: Span {
+                                        lo: 1,
+                                        hi: 27,
+                                    },
+                                    kind: Operation,
+                                    name: Ident {
+                                        id: NodeId(
+                                            4294967295,
+                                        ),
+                                        span: Span {
+                                            lo: 11,
+                                            hi: 15,
+                                        },
+                                        name: "Main",
+                                    },
+                                    generics: [],
+                                    input: Pat {
+                                        id: NodeId(
+                                            4294967295,
+                                        ),
+                                        span: Span {
+                                            lo: 15,
+                                            hi: 17,
+                                        },
+                                        kind: Tuple(
+                                            [],
+                                        ),
+                                    },
+                                    output: Ty {
+                                        id: NodeId(
+                                            4294967295,
+                                        ),
+                                        span: Span {
+                                            lo: 20,
+                                            hi: 24,
+                                        },
+                                        kind: Path(
+                                            Path {
+                                                id: NodeId(
+                                                    4294967295,
+                                                ),
+                                                span: Span {
+                                                    lo: 20,
+                                                    hi: 24,
+                                                },
+                                                segments: None,
+                                                name: Ident {
+                                                    id: NodeId(
+                                                        4294967295,
+                                                    ),
+                                                    span: Span {
+                                                        lo: 20,
+                                                        hi: 24,
+                                                    },
+                                                    name: "Unit",
+                                                },
+                                            },
+                                        ),
+                                    },
+                                    functors: None,
+                                    body: Block(
+                                        Block {
+                                            id: NodeId(
+                                                4294967295,
+                                            ),
+                                            span: Span {
+                                                lo: 25,
+                                                hi: 27,
+                                            },
+                                            stmts: [],
+                                        },
+                                    ),
+                                },
+                            ),
+                        },
+                    ],
+                },
+            ],
+            [
+                Error(
+                    Token(
+                        Eof,
+                        Ident,
+                        Span {
+                            lo: 28,
+                            hi: 32,
+                        },
+                    ),
+                ),
+            ],
+        )"#]]
+    .assert_eq(&result);
+}
diff --git a/language_service/src/state/tests.rs b/language_service/src/state/tests.rs
index 70bd041e..53acec1f 100644
--- a/language_service/src/state/tests.rs
+++ b/language_service/src/state/tests.rs
@@ -171,13 +171,29 @@ async fn close_last_doc_in_project() {
                             Error(
                                 Parse(
                                     Error(
-                                        ExpectedItem(
+                                        Token(
+                                            Eof,
                                             ClosedBinOp(
                                                 Slash,
                                             ),
                                             Span {
                                                 lo: 59,
-                                                hi: 59,
+                                                hi: 60,
+                                            },
+                                        ),
+                                    ),
+                                ),
+                            ),
+                        ),
+                        Frontend(
+                            Error(
+                                Parse(
+                                    Error(
+                                        ExpectedItem(
+                                            Eof,
+                                            Span {
+                                                lo: 59,
+                                                hi: 140,
                                             },
                                         ),
                                     ),
@@ -296,11 +312,27 @@ async fn compile_error() {
                             Error(
                                 Parse(
                                     Error(
-                                        ExpectedItem(
+                                        Token(
+                                            Eof,
                                             Ident,
                                             Span {
                                                 lo: 0,
-                                                hi: 0,
+                                                hi: 9,
+                                            },
+                                        ),
+                                    ),
+                                ),
+                            ),
+                        ),
+                        Frontend(
+                            Error(
+                                Parse(
+                                    Error(
+                                        ExpectedItem(
+                                            Eof,
+                                            Span {
+                                                lo: 0,
+                                                hi: 9,
                                             },
                                         ),
                                     ),
@@ -1362,13 +1394,29 @@ async fn close_doc_prioritizes_fs() {
                             Error(
                                 Parse(
                                     Error(
-                                        ExpectedItem(
+                                        Token(
+                                            Eof,
                                             ClosedBinOp(
                                                 Slash,
                                             ),
                                             Span {
                                                 lo: 59,
-                                                hi: 59,
+                                                hi: 60,
+                                            },
+                                        ),
+                                    ),
+                                ),
+                            ),
+                        ),
+                        Frontend(
+                            Error(
+                                Parse(
+                                    Error(
+                                        ExpectedItem(
+                                            Eof,
+                                            Span {
+                                                lo: 59,
+                                                hi: 140,
                                             },
                                         ),
                                     ),
@@ -2120,11 +2168,27 @@ async fn error_from_dependency_reported() {
                         Error(
                             Parse(
                                 Error(
-                                    ExpectedItem(
+                                    Token(
+                                        Eof,
                                         Ident,
                                         Span {
                                             lo: 0,
-                                            hi: 0,
+                                            hi: 13,
+                                        },
+                                    ),
+                                ),
+                            ),
+                        ),
+                    ),
+                    Frontend(
+                        Error(
+                            Parse(
+                                Error(
+                                    ExpectedItem(
+                                        Eof,
+                                        Span {
+                                            lo: 0,
+                                            hi: 13,
                                         },
                                     ),
                                 ),
diff --git a/library/qs_source/src/std/convert.qs b/library/std/src/convert.qs
similarity index 100%
rename from library/qs_source/src/std/convert.qs
rename to library/std/src/convert.qs
diff --git a/library/qs_source/src/std/core.qs b/library/std/src/core.qs
similarity index 100%
rename from library/qs_source/src/std/core.qs
rename to library/std/src/core.qs
diff --git a/library/qs_source/src/std/diagnostics.qs b/library/std/src/diagnostics.qs
similarity index 100%
rename from library/qs_source/src/std/diagnostics.qs
rename to library/std/src/diagnostics.qs
diff --git a/library/qs_source/src/std/internal.qs b/library/std/src/internal.qs
similarity index 100%
rename from library/qs_source/src/std/internal.qs
rename to library/std/src/internal.qs
diff --git a/library/qs_source/src/std/intrinsic.qs b/library/std/src/intrinsic.qs
similarity index 100%
rename from library/qs_source/src/std/intrinsic.qs
rename to library/std/src/intrinsic.qs
diff --git a/library/qs_source/src/std/logical.qs b/library/std/src/logical.qs
similarity index 100%
rename from library/qs_source/src/std/logical.qs
rename to library/std/src/logical.qs
diff --git a/library/qs_source/src/std/math.qs b/library/std/src/math.qs
similarity index 100%
rename from library/qs_source/src/std/math.qs
rename to library/std/src/math.qs
diff --git a/library/qs_source/src/std/measurement.qs b/library/std/src/measurement.qs
similarity index 100%
rename from library/qs_source/src/std/measurement.qs
rename to library/std/src/measurement.qs
diff --git a/library/qs_source/src/std/modern_api.qs b/library/std/src/modern_api.qs
similarity index 100%
rename from library/qs_source/src/std/modern_api.qs
rename to library/std/src/modern_api.qs
diff --git a/library/qs_source/src/std/qir.qs b/library/std/src/qir.qs
similarity index 100%
rename from library/qs_source/src/std/qir.qs
rename to library/std/src/qir.qs
diff --git a/library/qs_source/src/std/random.qs b/library/std/src/random.qs
similarity index 100%
rename from library/qs_source/src/std/random.qs
rename to library/std/src/random.qs
diff --git a/library/qs_source/src/std/re.qs b/library/std/src/re.qs
similarity index 100%
rename from library/qs_source/src/std/re.qs
rename to library/std/src/re.qs
diff --git a/library/qs_source/src/std/unstable_arithmetic.qs b/library/std/src/unstable_arithmetic.qs
similarity index 100%
rename from library/qs_source/src/std/unstable_arithmetic.qs
rename to library/std/src/unstable_arithmetic.qs
diff --git a/library/qs_source/src/std/unstable_arithmetic_internal.qs b/library/std/src/unstable_arithmetic_internal.qs
similarity index 100%
rename from library/qs_source/src/std/unstable_arithmetic_internal.qs
rename to library/std/src/unstable_arithmetic_internal.qs
diff --git a/library/qs_source/src/std/unstable_state_preparation.qs b/library/std/src/unstable_state_preparation.qs
similarity index 100%
rename from library/qs_source/src/std/unstable_state_preparation.qs
rename to library/std/src/unstable_state_preparation.qs
diff --git a/library/qs_source/src/std/unstable_table_lookup.qs b/library/std/src/unstable_table_lookup.qs
similarity index 100%
rename from library/qs_source/src/std/unstable_table_lookup.qs
rename to library/std/src/unstable_table_lookup.qs
diff --git a/pip/tests/test_interpreter.py b/pip/tests/test_interpreter.py
index 4d4cc287..86838e18 100644
--- a/pip/tests/test_interpreter.py
+++ b/pip/tests/test_interpreter.py
@@ -184,7 +184,7 @@ def test_target_error() -> None:
         e.interpret(
             "operation Program() : Result { use q = Qubit(); if M(q) == Zero { return Zero } else { return One } }"
         )
-    assert str(excinfo.value).startswith("Qsc.BaseProfCk.ResultLiteral") != -1
+    assert str(excinfo.value).startswith("Qsc.CapabilitiesCk.UseOfDynamicBool")
 
 
 def test_qirgen_compile_error() -> None:
@@ -192,7 +192,7 @@ def test_qirgen_compile_error() -> None:
     e.interpret("operation Program() : Int { return 0 }")
     with pytest.raises(QSharpError) as excinfo:
         e.qir("Foo()")
-    assert str(excinfo.value).startswith("Qsc.Resolve.NotFound") != -1
+    assert str(excinfo.value).startswith("Qsc.Resolve.NotFound")
 
 
 def test_error_spans_from_multiple_lines() -> None: